您的位置:首页 > 其它

浅析memmove函数之内存重叠

2018-02-07 11:07 162 查看
  话说上一节说到memcpy函数实现没有考虑内存重叠问题,难道C库函数故意留一个bug吗?当然不是了,memmove函数就弥补了这个不足哦,是不是以前一直觉得这两个函数没啥区别呢,实际上区别大了去了,下面详细道来。

  老话常谈,C语言中操作内存的最小单元当属字节,假如100个字节的内存需要搬运,恰巧的是目的内存的100字节中,包含了源地址中的50个,假如依旧按照memcpy方式来的话,保证那50个字节重叠部分不是你想要的,不信就弄一个100字节的数组试一试喽。

1. 内存重叠原理分析

  这里借用一个图来用一下,图上有该作者的链接,有兴趣者可以访问哦,替他打一波广告。



  图中展示了两种内存重叠的情况,乍一看还挺复杂,如何快速识破他的真面目呢?其实,搞清楚两点,一切反动派都是纸老虎,哈哈

内存是否重叠 做减法

  内存地址间距(src-dst)能否装下count字节,装不下的话,src拷贝后肯定会占用dst的部分内存啦,这里只需做减法,比大小,不看正负

拷贝过程 看方向

  搬砖工从src位置一块砖一块砖的搬到dst位置,从src到dst这个方向与内存增长方向一致,那完了,搬着石头砸自己的脚,肯定破坏了自己的内容,脚疼啊。若二者方向相反,src已经搬完了,腾空了内存,正好供dst用啊,不重叠喽,感觉说的好啰嗦,有助理解吧,对应图例,图一重叠但不影响搬运内容,图二重叠但影响内容,我们memmove函数致力于解决这个问题。

2. memmove函数原型

先看函数原型吧,好眼熟,跟memcpy一摸一样呀,难道眼花了,没错就是一样。

void* my_memmove(void* dst, const void* src, unsigned int size)


  面对上图中内存重叠的情况,我们需要对这种情况进行判断,然后针对拷贝方向与内存增长方向一致的情况做出讨论和处理,怎么处理呢?再想想我们的两条原则,第一条原则内存的相对位置我们可改变不了,也就是间距,这是固定的。好吧那就只有改变第二条了,第二条什么来着,方向,方向,方向,重要的说三遍。

  好吧,方向怎么改呢?内存方向?那改屁啊,内存自诞生起就定好的,那就只能改他了,哈哈哈,拷贝方向,长话短说,我先拷贝src的最高字节到dst的最高字节,依次拷次高字节,就是反着拷,来看具体实现:

void *memmove(void *dest,void *src,unsigned int size)
{
char *d=(char *)dest; //牛鬼蛇神都得转存成字节,字节是最基本拷贝单元呢
char *s=(char*)src;    //源地址和目的地址都得转,别忘了
if(d==NULL||s==NULL||size<0) return NULL; //给我空地址,我可不要,扔回去
if(s<d&&s+size>d){      //两个条件,方向和间距喽
s=s+size-1;             //这个是重叠第二种情况,需要调整拷贝方向
d=d+size-1;             //把指针指向需要拷贝的最末字节(以前是最开始字节)
while(size--) *d--=*s--; //搬一个减一个地址,直到完成所有拷贝
}else{
while(size--) *d++=*s++;  //这是第一种情况,及不重叠的情况哦
}
return dest;
}


哈哈,一气呵成,细细思考这些细节,还是耐人寻味的,这就是C语言的魅力吧,换个思路,每个细胞里面都包含了母体的全部信息,一叶知秋,希望能够通过这些细致的思考,迅速提示对C语言的深入认识喽
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息