memcpy和memmove的区别
这两个函数都是将s2指向位置的n字节数据拷贝到s1指向的位置。memcpy 假定两块内存区域没有数据重叠,而 memmove 没有这个前提条件。如果复制的两个区域存在重叠时使用memcpy,其结果是不可预知的( 未定义的 ),有可能成功也有可能失败。原因如下:
-
当src地址大于dest地址时,即使有重叠,也可以正常复制。
-
当src地址小于dest地址时,若重叠,则复制发生异常。
这种情况下,src的地址小于dest的地址,拷贝前3个字节没问题,但是拷贝第4,5个字节时,原有的内容已经被src拷贝过来的字符覆盖了,所以已经丢失原来src的内容。
然而,vs2019下进行试验,发现即使是在第二种情况下,memcpy与memmove的结果相同,都正确,原因可能是 memcpy 目前也采用了 memmove 的方式。
memmove的实现:
void *memmove(void *dest, const void *src, size_t n)
{
unsigned char *pd = dest;
const unsigned char *ps = src;
if((ps + n > pd)&& ps < pd)
for (pd += n, ps += n; n--;)
*--pd = *--ps;
else
while(n--)
*pd++ = *ps++;
return dest;
}
memmove会对拷贝的数据作检查,确保内存没有覆盖,如果发现会覆盖数据,简单的实现是调转开始拷贝的位置,从尾部开始拷贝 。但是实际在 C99 实现中,是将内容拷贝到临时空间,再拷贝到目标地址中 :
void *memmove(void *dest, const void *src, size_t n) { unsigned char tmp[n]; memcpy(tmp,src,n); memcpy(dest,tmp,n); return dest; }
memcpy的实现:
void *memcpy(void *dest, const void *src, size_t n)
{
char *dp = dest;
const char *sp = src;
while (n--)
*dp++ = *sp++;
return dest;
}
//目前memcpy已做改进,以下为源码:
void *memcpy(void *dst, const void *src, size_t len)
{
if(NULL == dst || NULL == src){
return NULL;
}
void *ret = dst;
if(dst <= src || (char *)dst >= (char *)src + len){
//没有内存重叠,从低地址开始复制
while(len--){
*(char *)dst = *(char *)src;
dst = (char *)dst + 1;
src = (char *)src + 1;
}
}else{
//有内存重叠,从高地址开始复制
src = (char *)src + len - 1;
dst = (char *)dst + len - 1;
while(len--){
*(char *)dst = *(char *)src;
dst = (char *)dst - 1;
src = (char *)src - 1;
}
}
return ret;
}
本文链接:
/archives/memcpy-memmove
版权声明:
本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自
后端技术分享!
喜欢就支持一下吧