linux内核中memcpy和memmove函数的区别和实现
CPU architecture:ARM
Author:ce123(http://blog.csdn.net/ce123)
- memcpy是把src指向的对象中的size个字符拷贝到dest所指向的对象中,返回指向结果对象的指针.
- 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怎么办呢,看函数,它是从后面往前拷贝,这样就能正确拷贝数据了.根据上面的分析,理解下面的代码应该是一件很容易的事情.
[plain]view plaincopyprint?
- 551#ifndef__HAVE_ARCH_MEMCPY
- 552/**
- 553*memcpy-Copyoneareaofmemorytoanother
- 554*@dest:Wheretocopyto
- 555*@src:Wheretocopyfrom
- 556*@count:Thesizeofthearea.
- 557*
- 558*YoushouldnotusethisfunctiontoaccessIOspace,usememcpy_toio()
- 559*ormemcpy_fromio()instead.
- 560*/
- 561void*memcpy(void*dest,constvoid*src,size_tcount)
- 562{
- 563char*tmp=dest;
- 564constchar*s=src;
- 565
- 566while(count--)
- 567*tmp++=*s++;
- 568returndest;
- 569}
- 570EXPORT_SYMBOL(memcpy);
- 571#endif
- 572
- 573#ifndef__HAVE_ARCH_MEMMOVE
- 574/**
- 575*memmove-Copyoneareaofmemorytoanother
- 576*@dest:Wheretocopyto
- 577*@src:Wheretocopyfrom
- 578*@count:Thesizeofthearea.
- 579*
- 580*Unlikememcpy(),memmove()copeswithoverlappingareas.
- 581*/
- 582void*memmove(void*dest,constvoid*src,size_tcount)
- 583{
- 584char*tmp;
- 585constchar*s;
- 586
- 587if(dest<=src){
- 588tmp=dest;
- 589s=src;
- 590while(count--)
- 591*tmp++=*s++;
- 592}else{
- 593tmp=dest;
- 594tmp+=count;
- 595s=src;
- 596s+=count;
- 597while(count--)
- 598*--tmp=*--s;
- 599}
- 600returndest;
- 601}
- 602EXPORT_SYMBOL(memmove);
- 603#endif
linux内核memcpymemmove函 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)