1 函数原型及用法
(1) memcpy
【函数原型】
void *memcpy(void * dst, const void *src, size_t count);
C99原型:
void *memcpy(void * restrict dst, const void *restrict src, size_t count);
【解析】
memcpy用于内存拷贝,在执行操作时,如果src和dst的地址重叠,拷贝会发生错误。C99中引入关键字restrict 进行了内存访问限制。
(2) memmove
【函数原型】
void *memmove(void *dst, const void *src, size_t count);
memmove,顾名思义就好像内存发生了搬移,由src搬移到dst地址上。搬移过程中,好像先将src搬移到一个temp的地址,再将temp搬移到dst。如果src和dst的地址重叠,也不会发生错误。但执行的效率比memcpy低。
(3) strcpy
【函数原型】
char *(const char *dst, const char *src);
【解析】
strcpy只能用于字符串(const char *)拷贝,而memxxx无此限制,可以处理包括NUL('\0')在内的任意字节。返回值是第1个参数的一份拷贝,即一个指向目标字符数组的指针。
2 关键字restrict
提到memcpy和memmove就不能不说关键字restrict ,注意到memcpy中加了restrict ,而memmove中则没有。加上restrict 关键字后,表示指针是相应数据的唯一访问方式。因此,memcpy中dst和src指针都是相应数据的唯一访问方式,这就决定了两个内存地址不能重叠。而memmove中因为move时开辟了临时空间,无此限制。
注意strcpy原型也无关键字restrict 限制,因此复制的过程中,src和dst也可能存在内存重叠现象。
【增-2012.3.13】3 Linux-2.6.23源码分析
(1) memcpy
Linux-2.6.23/lib/string.h(Line516-536) #ifndef __HAVE_ARCH_MEMCPY /** * memcpy - Copy one area of memory to another * @dest: Where to copy to * @src: Where to copy from * @count: The size of the area. * * You should not use this function to access IO space, use memcpy_toio() * or memcpy_fromio() instead. */ void *memcpy(void *dest, const void *src, size_t count) { char *tmp = dest; const char *s = src; while (count--) *tmp++ = *s++; return dest; } EXPORT_SYMBOL(memcpy); #endif
(2) memmove
Linux-2.6.23/lib/string.h(Line536-568) #ifndef __HAVE_ARCH_MEMMOVE /** * memmove - Copy one area of memory to another * @dest: Where to copy to * @src: Where to copy from * @count: The size of the area. * * Unlike memcpy(), memmove() copes with overlapping areas. */ void *memmove(void *dest, const void *src, size_t count) { char *tmp; const char *s; if (dest <= src) { tmp = dest; s = src; while (count--) *tmp++ = *s++; } else { tmp = dest; tmp += count; s = src; s += count; while (count--) *--tmp = *--s; } return dest; } EXPORT_SYMBOL(memmove); #endif
【分析】
(1) memmove在复制是开辟了一个tmp和s的临时指针,而memcpy没有,这样做的优点在于不会改变src的数据,缺点是效率有所下降;
(2) 当dest指针的地址小于等于src的地址时,逐个复制时,dest++的地址总是小于等于src++的地址,不会因为地址重叠出现问题,因此采用类似于如下方式进行复制:
while (count--) *tmp++ = *s++;
(3) 当dest指针的地址大于src时,memcpy没有采取任何措施,保护src++的数据。
(4) 当dest指针的地址大于src时,memmove采用反序的方式进行复制,保证了从src取得数据的完整性,即在count范围内,src的数据不会因为src与dest地址重叠,而被覆盖。