当前位置: 首页 > news >正文

memmove 和 memcpy的区别

函数原型及作用

memcpy 和 memmove 都是C语言中的库函数,在头文件string.h中,作用是拷贝一定长度的内存的内容,原型分别如下:

void* memcpy(void *dst, const void *src, size_t count);
void* memmove(void *dst, const void *src, size_t count);

他们的作用是一样的,唯一的区别是,当内存发生局部重叠的时候,memmove保证拷贝的结果是正确的,memcpy不保证拷贝的结果的正确。

  • 第一种情况下,拷贝重叠的区域不会出现问题,内容均可以正确的被拷贝。
  • 第二种情况下,问题出现在右边的两个字节,这两个字节的原来的内容首先就被覆盖了,而且没有保存。所以接下来拷贝的时候,拷贝的是已经被覆盖的内容,显然这是有问题的。

实际上,memcpy只是memmove的一个子集。

二者的c语言实现很简单,有兴趣的朋友可以去看看。在实际情况下,这两个函数都是用汇编实现的。

memmove在copy两个有重叠区域的内存时可以保证copy的正确,而memcpy就不行了,但memcpy比memmove的速度要快一些,如:
char s[] = “1234567890”;
char* p1 = s;
char* p2 = s+2;
memcpy(p2, p1, 5) 与 memmove(p2, p1, 5) 的结果就可能是不同的,memmove()可以将p1的头5个字符"12345"正确拷贝至p2,而memcpy()的结果就不一定正确了

变态的命名

我们在写程序时,一般讲究见到变量的命名,就能让别人基本知道该变量的含义。memcpy内存拷贝,没有问题;memmove,内存移动?错,如果这样理解的话,那么这篇文章你就必须要好好看看了,memmove还是内存拷贝。那么既然memcpy和memmove二者都是内存拷贝,那二者究竟有什么区别呢?

memcpy

你有没有好好的参加过一场C++笔试。让你写出memcpy的实现,这是多么常见的笔试题啊。现在,拿起你的演算纸和笔;是的,是笔和纸,不是让你在你的IDE上写。写不出来?看下面吧:

void *memcpy(void *dest, const void *src, size_t count)
{assert(dest != NULL && src != NULL);char *p = (char *)dest;char *q = (char *)src;if (p == q)return p;while (count--){*p++ = *q++;}return des;
}

memcpy的实现很简单,一般在笔试时,出现写源码的题目,无非就是需要注意以下几点:

  1. 确定函数原型;
  2. 判断参数合法性;
  3. 逻辑实现(考虑各种情况,统称逻辑实现);
  4. 错误处理。

当然了,我的这个没有错误处理,也不需要错误处理。上面,我写出了memcpy的实现源码,实现原理如下图所示:

这样下去,上面的代码会运行的很好,如果出现下面的情况呢?

i、n、k的内存和J、e、l的内存地址重合了,现在再使用上面的代码进行copy时,会出现什么问题呢?你有没有想过这个问题。如果没有,那就现在想想,不急着阅读下面的内容。

然后,我再留一个问题,上面的代码中,为什么都需要将void *转换成char *呢?

memmove

memmove也是用来实现内存的直接拷贝的。说起这个命名,我个人觉的多少还是有点坑的。既然memmove也是用来内存数据移动的,那就先来看看memmove的实现源码。

void *memmove(void *dest, const void *src, size_t count)
{assert(dest != NULL || src != NULL)if (dst < src){char *p = (char *)dest;char *q = (char *)src;while (count--){*p++ = *q++;}}else{char *p = (char *)dest + count;char *q = (char *)src + count;while (count--){*--p = *--q;}}return dest;
}

从源码看,memmove的确比memcpy复杂一些;再仔细一看,多了些什么?哦,多了一个else分支,而正是这个else分支,就处理了当src和dest的内存重合的问题。

memcpy和memmove的比较

从实现源码中的确能看出一些猫腻,当出现了src和dest的内存有重合的时机时,memmove的处理规则是从后往前进行copy。当然了,重合的问题,需要考虑的以下两种场合。

如图所示,当出现(1)对应的情况时,就需要先从src的头部开始复制;也就是memmove源码中的if分支,这部分源码和memcpy的实现是一致的;当出现(2)对应的情况时,就需要先从src的尾部开始复制,防止出现了覆盖现象。这就是memmove比memcpy多的一个考虑点,所以说,在实际使用时,使用memmove是比memcpy更安全的。

http://www.lryc.cn/news/254833.html

相关文章:

  • C实现的双向链表队列
  • 自适应中值滤波器的python代码实现-----冈萨雷斯数字图像处理
  • Python作业答疑_6.22~6.25
  • Uber Go 语言编码规范
  • UniRepLKNet:用于音频、视频、点云、时间序列和图像识别的通用感知大内核ConvNet
  • Http协议与Tomcat
  • Spring AOP从入门到精通
  • Tap虚拟网卡
  • 【数电笔记】53-与非门构成的基本RS触发器
  • kubernetes(k8s)容器内无法连接同所绑定的Service ClusterIP问题记录
  • Hadoop入门学习笔记
  • 堆栈,BSS,DATA,TEXT
  • Java八股文面试全套真题【含答案】-JSON篇
  • 数据库管理-第119期 记一次迁移和性能优化(202301130)
  • 【云原生-K8s】镜像漏洞安全扫描工具Trivy部署及使用
  • 【Docker】Swarm的ingress网络
  • gcc安全特性之FORTIFY_SOURCE
  • 【JUC】二十、volatile变量的特点与使用场景
  • 软件工程期末复习(2)
  • [vue3] 使用 vite 创建vue3项目的详细流程
  • #HarmonyOS:软件安装window和mac预览Hello World
  • nginx 一键切换停机维护页面 —— 筑梦之路
  • Python作业答疑
  • 计算机网络实用工具之Hydra
  • AUTOSAR 入门
  • 新版IDEA中,module模块无法被识别,类全部变成咖啡杯无法被识
  • vue.js el-table 动态单元格列合并
  • word模板导出word文件
  • debianubuntu的nvidia驱动升级
  • 【开源视频联动物联网平台】视频接入网关的用法