P.S 我知道
memcpy
不应该用于将数据复制到重叠的内存地址,而应该使用 memmove
来代替。
根据我对
memcpy
的理解,该函数基本上将每个字节从源地址顺序复制到目标地址指定的字节数。所以理论上,给出代码:
int main(void){
int arr[] = {1, 2, 3, 0, 0};
memcpy(arr + 1, arr, 3 * sizeof(arr[0]));
return 0;
}
结果不应该是
arr = {1, 1, 1, 1, 0}
吗,因为arr[0]
被复制到下一个位置,再次复制等等,导致全是1?
然而,实际输出是
arr = {1, 1, 2, 3, 0};
,其中元素似乎被正确复制。为什么会出现这种情况?我最好的猜测是 memcpy
使用某种缓冲区来保存正在复制的元素的副本,并复制缓冲区中的每个字节而不是更新的数组,以避免损坏后续值。
我还尝试复制数组的较长部分,看看是否存在 8 字节缓冲区之类的东西:
int arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 0, 0, 0, 0, 0, 0, 0};
memcpy(arr + 8, arr, 16*sizeof(arr[0]));
并且输出仍然与前面的示例一致:
arr = {1, 2, 3, 4, 5, 6, 7, 8, 1, 2....15, 16};
没有具体说明它如何进行复制,因此编译器可以生成最快的任何程序集。这可以是从前到后或从后到前。它可能涉及在破坏目标字节之前将其拉入寄存器,甚至对 memcpy 和 memmove 使用完全相同的代码来最小化指令缓存。某些处理器上还有特定的向量运算,可以并行操作一系列字节。
如果您好奇您的特定编译器如何针对此特定代码执行此操作(没有说明它不能在其他地方以不同方式编译它),某些编译器可以通过方法查看生成的程序集。对于 gcc,它是
gcc -S foo.c
。