迅雷面试题:memcpy和memmove的区别

转载出:http://blog.csdn.net/zdl1016/article/details/8680864

其实很早就知道两个函数其中有一个在面临内存覆盖时行为有点特别, 但是工作中很少用到此场景, 也就没有深究. 现在居然面试遇到了, 那就把研究清楚吧.

memcpy 简单粗暴, 不考虑内存重叠问题. 后果程序员自负

memmove 比memcpy多了层检查内存重叠的考虑,如果发现重叠, 则反向拷贝, 性能和memcpy基本一样. 就是多了个检查是否重叠的代码.

综上所述, 以后干脆就用memmove吧. 省的那么多事. 反正性能几乎没有损失.

 

测试代码如下 

[cpp]  view plain copy
  1. int main ()  
  2. {  
  3.     char c1[20] =  {0};  
  4.     snprintf(c1, sizeof(c1), "hello world");  
  5.     printf("original str   : %s",c1);                                                                                                                                              
  6.     printf("\n");  
  7.   
  8.     memcpy(c1+3, c1, 9);   
  9.     printf("memcpy result  : %s",c1);  
  10.     printf("\n");  
  11.   
  12.     snprintf(c1, sizeof(c1), "hello world");  
  13.     memmove(c1+3, c1, 9);   
  14.     printf("memmove result : %s",c1);  
  15.     printf("\n");  
  16.   
  17.     return 0;  
  18. }  


输出结果如下:

original str   : hello world
memcpy result  : helhellellol      // 完全乱了
memmove result : helhello wor // 正确处理了内存重叠问题

 

扩展阅读, memmove是如何实现的?

[cpp]  view plain copy
  1. 由于该函数比memcpy安全的一点在于要考虑内存是否重叠,如果重叠则反向copy避免还没有copy的地方被覆盖.  
  2. 实现要点:  
  3. 1) 检查是否内存重叠,如果没有重叠,则直接调用memcpy.  
  4. 2) 如果重叠,则从src+len,到dst+len倒序copy.  
  5.    此时不能利用memcpy,因为memcpy是正向copy的. 需要按照类似memcpy的实现,在汇编指令中把cld替换为std,把方向标记位改下即可.  
  6.   
  7. 内存重叠的含义是什么呢?  
  8. 1)如果dst < src 则无论dst和src距离多远都没问题.  
  9. 2)如果dst > src,并且两者的差值>=len, 则虽然dst在后面,因距离很远, 也没有重叠  
  10. 3)如果dst > src 并且差值<len, 那么copy时则会重叠导致不可预测的结果.  
  11.   
  12. ========================================================  
  13. glibc 2.17 的memmove源码如下  
  14.   
  15.   
  16. rettype  
  17. MEMMOVE (a1, a2, len)  
  18.      a1const void *a1;  
  19.      a2const void *a2;  
  20.      size_t len;  
  21. {  
  22.   unsigned long int dstp = (long int) dest;  
  23.   unsigned long int srcp = (long int) src;  
  24.   
  25.   // 根据上面的三种情况, 这里由于dstp,srcp都是无符号的即使dstp<srcp, 负值对应的无符号数也是很大的值.  
  26.   /* This test makes the forward copying code be used whenever possible. 
  27.      Reduces the working set.  */  
  28.   if (dstp - srcp >= len) /* *Unsigned* compare!  */  
  29.     {  
  30.       /* Copy from the beginning to the end.  */  
  31.   
  32.   
  33. #if MEMCPY_OK_FOR_FWD_MEMMOVE  
  34.       dest = memcpy (dest, src, len);  
  35. #else  
  36.       ... 这里略过, 其实就是memcpy的实现  
  37. #endif /* MEMCPY_OK_FOR_FWD_MEMMOVE */  
  38.     }  
  39.   else  
  40.     {  
  41.       /* Copy from the end to the beginning.  */  
  42.       srcp += len;  
  43.       dstp += len;  
  44.   
  45.   
  46.       /* If there not too few bytes to copy, use word copy.  */  
  47.       if (len >= OP_T_THRES)  
  48.  {  
  49.    /* Copy just a few bytes to make DSTP aligned.  */  
  50.    len -= dstp % OPSIZ;  
  51.    // 这里利用了反向copy的宏. BWD means backward​  
  52.    BYTE_COPY_BWD (dstp, srcp, dstp % OPSIZ);  
  53.   
  54.   
  55.    /* Copy from SRCP to DSTP taking advantage of the known 
  56.       alignment of DSTP.  Number of bytes remaining is put 
  57.       in the third argument, i.e. in LEN.  This number may 
  58.       vary from machine to machine.  */  
  59.   
  60.   
  61.    WORD_COPY_BWD (dstp, srcp, len, len);  
  62.   
  63.   
  64.    /* Fall out and copy the tail.  */  
  65.  }  
  66.   
  67.   
  68.       /* There are just a few bytes to copy.  Use byte memory operations.  */  
  69.       BYTE_COPY_BWD (dstp, srcp, len);  
  70.     }  
  71.   
  72.   
  73.   RETURN (dest);  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值