使用memcpy()将缓冲区的尾部移动到它的开头? (交叠)

时间:2018-05-17 22:19:50

标签: c buffer memcpy

我有二进制文件读取缓冲区,它读取可变长度的结构。在缓冲区末尾附近总会有不完整的结构。我想将这样的缓冲区尾移到它的开头,然后在下一个文件读取期间读取buffer_size - tail_len个字节。像这样:

char[8192] buf;
cur = 0, rcur = 0;
while(1){
  read("file", &buf[rcur], 8192-rcur);
  while (cur + sizeof(mystruct) < 8192){
    mystruct_ptr = &buf[cur];
    if (mystruct_prt->tailsize + cur >= 8192) break; //incomplete
    //do stuff
    cur += sizeof(mystruct) + mystruct_ptr->tailsize;
  }
  memcpy(buf,&buf[cur],8192-cur);
  rcur=8192-cur;
  cur = 0;
}

如果尾部很小且缓冲区很大,它应该可以正常,因为memcpy 很可能在单次复制迭代期间不会与复制的内存段重叠。然而,当尾巴变大时,它听起来有点冒险 - 大于50%的缓冲区。

如果缓冲区非常庞大且尾部也很大,那么它仍然应该没问题,因为在单个操作中可以复制多少数据的物理限制,如果我没记错的话,对于使用向量单元的现代x86_64 CPU来说,这是512字节。我考虑添加检查尾部长度的条件,如果它与缓冲区的大小相比太大,执行天真的逐字节复制,但问题是:

memcpy

1 个答案:

答案 0 :(得分:2)

根据标准,如果源和目标区域重叠,memcpy()具有未定义的行为。区域有多大或者有多少重叠并不重要。未定义的行为不能被认为是安全的。

如果您正在编写特定的实现,并且该实现定义了某些此类复制的行为,并且您不关心可移植性,那么您可以依赖于您的实现在这方面的特定行为。但我建议不要。这将是一个令人讨厌的错误等待咬人决定使用代码与其他一些实现。甚至可能是未来你。

在这种特殊情况下,使用专用于此目的的memmove()替代方案,会使memcpy()赌博完全鲁莽。