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