复制重叠内存

各种标准库函数的作用是将字节序列从一个存储区域复制到另一个存储区域。当源和目标区域重叠时,大多数这些函数都具有未定义的行为。

例如,这……

#include <string.h> /* for memcpy() */

char str[19] = "This is an example";
memcpy(str + 7, str, 10);

…尝试复制 10 个字节,其中源和目标内存区域重叠三个字节。想象:

               overlapping area
               |
               _ _
              |   |
              v   v
T h i s   i s   a n   e x a m p l e \0
^             ^
|             |
|             destination
|
source

由于重叠,因此未定义结果行为。

在这种限制的标准库函数中有 memcpy()strcpy()strcat()sprintf()sscanf()。标准说明了这些和其他几个功能:

如果在重叠的对象之间进行复制,则行为未定义。

memmove() 函数是此规则的主要例外。其定义指定该函数的行为就像首先将源数据复制到临时缓冲区然后写入目标地址一样。重叠的源和目标区域没有例外,也不需要一个,因此在这种情况下 memmove() 具有明确定义的行为。

区别反映了效率。一般性权衡。诸如这些函数之类的复制通常发生在不相交的存储区域之间,并且通常可以在开发时知道存储器复制的特定实例是否属于该类别。假设非重叠提供了相对更有效的实现,当假设不成立时,这些实现不能可靠地产生正确的结果。大多数 C 库函数都允许更有效的实现,memmove() 填补空白,为源和目标可能或重叠的情况提供服务。然而,为了在所有情况下产生正确的效果,它必须执行额外的测试和/或采用相对低效的实现。