linux 内核中 memcpy 和 memmove 函数的区别和实现

144 篇文章 6 订阅
memcpy和memmove都是用于内存拷贝的C库函数,但处理内存区域重叠的方式不同。memcpy在内存重叠时可能导致数据错误,而memmove则能保证正确复制。当源和目标内存区域重叠时,memmove会根据情况选择从前向后或从后向前拷贝,确保数据完整性。在编写内核或驱动代码时,应优先考虑使用memmove以避免潜在的问题。
摘要由CSDN通过智能技术生成

memcpy 和memmove都是把 src 指向的对象中的 size 个字符拷贝到 dest 所指向的对象中,返回指向结果对象的指针。但这两个函数在处理内存区域重叠的方式不同。

注意 memmove 这个函数名称中有 "move" 这个单词,而实际上 src 处的数据仍然还在,并没有真的被 "移动" 了!这个函数名称有它的历史原因,是因为有了 memcpy 函数后,发现这个函数有问题,又发明了另一个没有问题的 memcpy 函数,但为了爆出兼容性依然保留了 memcpy 函数,而将新版本的 memcpy 函数改名为 memmove 函数.

内存重叠问题是指目的地址的内存空间的首地址,包含在源内存空间中,这两段内存空间有了交集,因而在使用 memcpy 进行内存复制操作时,这段重叠的内存空间会被破坏。这种情况在应用程序级代码中一般不会出现的,而在驱动或内核级代码中要十分小心,尽量使用 memmove 函数.

memcpy 对内存空间有要求的,dest 和 src 所指向的内存空间不能重叠,否则复制的数据是错误的。下面具体讲解一下这个错误是如何产生的.

如果内存空间布局入下图所示:

src 所指向的内存空间后面部分数据被新拷贝的数据给覆盖了 (也就是 dest<=src+size). 所以拷贝到最后,原来的数据肯定不是原来的数据,拷贝的数据也不是想要的数据 , 使用 memcpy 函数可以得到错误的结果.

再者,如果内存空间布局入下图所示:

虽然原来的数据不再是原来的数据 (dest+size>=src), 但拷贝的数据是原来的数据,使用 memcpy 函数可以得到正确的结果。因此,在使用 memcpy 这个函数之前,还需要做一个判断,如果 dest<=src 你才能使用这个函数不过完全没有必要,你直接使用 memmove 函数就可以了.memmove 在拷贝之前就做了一个判断,如果 dest <= src, 就按照 memcpy 的思路拷贝,如果 dest>src 怎么办呢,看函数,它是从后面往前拷贝,这样就能正确拷贝数据了。根据上面的分析,理解下面的代码应该是一件很容易的事情.

在Kernel version:2.6.32,CPU architecture:ARM的代码中,俩函数的定义如下:

551 #ifndef __HAVE_ARCH_MEMCPY
552 /**
553  * memcpy - Copy one area of memory to another
554  * @dest: Where to copy to
555  * @src: Where to copy from
556  * @count: The size of the area.
557  *
558  * You should not use this function to access IO space, use memcpy_toio()
559  * or memcpy_fromio() instead.
560  */
561 void *memcpy(void *dest, const void *src, size_t count)
562 {
563         char *tmp = dest;
564         const char *s = src;
565 
566         while (count--)
567                 *tmp++ = *s++;
568         return dest;
569 }
570 EXPORT_SYMBOL(memcpy);
571 #endif
572 
573 #ifndef __HAVE_ARCH_MEMMOVE
574 /**
575  * memmove - Copy one area of memory to another
576  * @dest: Where to copy to
577  * @src: Where to copy from
578  * @count: The size of the area.
579  *
580  * Unlike memcpy(), memmove() copes with overlapping areas.
581  */
582 void *memmove(void *dest, const void *src, size_t count)
583 {
584         char *tmp;
585         const char *s;
586 
587         if (dest <= src) {
588                 tmp = dest;
589                 s = src;
590                 while (count--)
591                         *tmp++ = *s++;
592         } else {
593                 tmp = dest;
594                 tmp += count;
595                 s = src;
596                 s += count;
597                 while (count--)
598                         *--tmp = *--s;
599         }
600         return dest;
601 }
602 EXPORT_SYMBOL(memmove);
603 #endif

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值