for循环最后一次迭代的指针变化

Posted

技术标签:

【中文标题】for循环最后一次迭代的指针变化【英文标题】:Pointer changes on last iteration of foor loop 【发布时间】:2018-09-12 11:06:35 【问题描述】:

我正在尝试在 C++ 中实现流式 ACN 接收器。为此,我创建了一个套接字,它从我从互联网上获得的测试源接收数据,但在本地运行。我收到数据就好了。但是,当我遍历根层中向量的各个字节时,我使用的指针在 for 循环的最后一次迭代中突然发生了变化。

我用于检查根层中的字段的代码如下所示。

// Locations for each field of the root layer in the packet in the raw data
char *preamble_size_p    = &this->raw[0];
char *postamble_size_p   = &this->raw[2];
char *acn_pid_p          = &this->raw[4];
char *flags_and_length_p = &this->raw[16];
char * const vector_p    = &this->raw[18];

int i;
uint8_t acn_pid_byte;

// get preamble size and check it
memcpy(&this->packet.root_layer.preamble_size, preamble_size_p, 2);
this->packet.root_layer.preamble_size = htons(this->packet.root_layer.preamble_size);
if (this->packet.root_layer.preamble_size != PREAMBLE_SIZE)
    return PACKET_ERROR_INVALID_PREAMBLE_SIZE;

// get postamble size and check it
memcpy(&this->packet.root_layer.postamble_size, postamble_size_p, 2);
this->packet.root_layer.postamble_size = htons(this->packet.root_layer.postamble_size);
if (this->packet.root_layer.postamble_size != POSTAMBLE_SIZE)
    return PACKET_ERROR_INVALID_POSTAMBLE_SIZE;

// get ACN pid and check if valid
for (i = 0; i < ACN_PID_SIZE; i++) 
    memcpy(&acn_pid_byte, acn_pid_p + i, 1);
    if (acn_pid_byte != ACN_PID[i]) 
        return PACKET_ERROR_INVALID_ACN_PID;
    
    this->packet.root_layer.acn_pid[i] = acn_pid_byte;


// get flags and length
memcpy(&this->packet.root_layer.flength, flags_and_length_p, 2);
this->packet.root_layer.flength = htons(this->packet.root_layer.flength);

/* ERROR HAPPENS IN LOOP BELOW */

// get vector and check if valid
uint32_t vector_bytes;
for (int k = 0; k < 4; k++) 
    memcpy(&vector_bytes + k, vector_p + k, 1);

如您所见,我将向量指针设为常量。它曾经像其他指针一样是常规指针。即使它是一个常数,它仍然会改变值。

raw 只是 char *raw,它在类的构造函数中分配,包含我的程序从源接收的字节。

char *raw;  
int size;

Packet(char *raw, int size) 
    this->raw = raw;
    this->size = size;

接收数据的代码。

char buffer[MAXLINE] = 0; // MAXLINE is 1024
n = recvfrom(sock_fd, (char *)buffer, MAXLINE, MSG_WAITALL, ( struct sockaddr *) &cli_addr, &len);
Packet packet = Packet(buffer, n);

在调用此packet.process() 之后立即开始运行顶部代码块中的代码。

我尝试在 gdb 中设置观察点,结果如下。

Breakpoint 1, Packet::processRootLayer (this=0x7fffffffd5e0) at server.cpp:45
45          memcpy(&this->packet.root_layer.preamble_size, preamble_size_p, 2);
(gdb) watch vector_p
Hardware watchpoint 2: vector_p
(gdb) c
Continuing.

Hardware watchpoint 2: vector_p

Old value = 0x7fffffffdcc2 ""
New value = 0x7fffffffdc00 ""
Packet::processRootLayer (this=0x7fffffffd5e0) at server.cpp:71
71          for (int k = 0; k < 4; k++) 
(gdb) 

任何帮助将不胜感激,如果您需要更多信息,请告诉我。

【问题讨论】:

哪个循环?哪个指针?您的代码太少而无法完整,而且无法知道您指的是什么……建议阅读:minimal reproducible example memcpy(&amp;vector_bytes + k, vector_p + k, 1); 调用未定义的行为,不确定您要在这里做什么 调用memcpy() 4次每次复制1个字节有什么意义?反正 ptr 算术是错误的,但即使不是,又有什么意义呢? 【参考方案1】:

您的vector_bytes 变量键入为uint32_t,因此&amp;vector_bytes + k 不会将k 字节添加到&amp;vector_bytes,它会添加k*sizeof(uint32_t) 字节。因此,您的 memcpy 会覆盖程序中的其他变量。

你可以像这样添加演员表

uint32_t vector_bytes;
for (int k = 0; k < 4; k++) 
    memcpy((char*)&vector_bytes + k, vector_p + k, 1);

或者你可以在没有循环的情况下做到这一点。

uint32_t vector_bytes;
memcpy(&vector_bytes, vector_p, 4);

简单得多。

【讨论】:

非常感谢约翰。那解决了它。我在 for 循环中使用它的原因是我想在调试时查看每个单独的字节。

以上是关于for循环最后一次迭代的指针变化的主要内容,如果未能解决你的问题,请参考以下文章

For循环中的Python最后一次迭代

为啥我在 PL/SQL 中的 for 循环没有打印出最后一次迭代

jQuery-UI 对话框仅显示 for 循环的最后一次迭代 [重复]

jQuery-UI对话框仅显示for循环的最后一次迭代[duplicate]

由于使用指向结构的指针的函数,for 循环意外中断

For Loop 仅在使用 FireStore 时进行最后一次迭代