内存拷贝函数 memcpy 的原理及实现

news2024/10/6 11:22:44

memcpy是memory copy的缩写,意为内存复制,在写C语言程序的时候,我们常常会用到它。它的函原型如下:

void *memcpy(void *dest, const void *src, size_t n);

它的功能是从src的开始位置拷贝n个字节的数据到dest。如果dest存在数据,将会被覆盖。memcpy函数的返回值是dest的指针。memcpy函数定义在string.h头文件里。自己实现的时候,最简单的方法是用指针按照字节顺序复制即可。但是性能太低:

  • 其一,一次一个字节效率太低,地址总线一般是32位,能搬运4字节,一次一个肯定慢的不行;
  • 其二,当内存区域重叠时会出现混乱情况。

下边根据以上两方面考虑提高memcpy函数的性能。首先考虑速度,可以按照 CPU 位宽搬运数据,效率更高,代码如下:

void * Memcpy1(void *dst, const void *src, size_t num)
{
 int nchunks = num/sizeof(dst);   /*按CPU位宽拷贝*/

 cout<<"sizeof(dst)是:"<<sizeof(dst)<<endl;

 int slice =   num%sizeof(dst);   /*剩余的按字节拷贝*/
 
 unsigned long * s = (unsigned long *)src;
 unsigned long * d = (unsigned long *)dst;
 
 while(nchunks--)
     *d++ = *s++;
     
 while (slice--)
     *((char *)d++) =*((char *)s++);
     
 return dst;
}

sizeof(dst)是4,即大部分数据每次按照4字节拷贝,最后不足4字节的再分别拷贝。但是内存区域出现重叠时,这种方法无法规避内存混乱问题。下面的方法能够规避内存重叠的bug,代码如下:

void *Memcpy2(void *dest, const void *src, size_t count)  
{  
 char *d;  
 const char *s;  
   
 if (((int)dest > ((int)src+count)) || (dest < src))  
    {  
    d = (char*)dest;  
    s = (char*)src;  
    while (count--)  
        *d++ = *s++;          
    }  
 else /* overlap */  
    {  
    d = (char *)((int)dest + count - 1); /* 指针位置从末端开始,注意偏置 */  
    s = (char *)((int)src + count -1);  
    while (count --)  
        *d-- = *s--;  
    }  
    
 return dest;  
}  

如果检测到内存区域有重叠部分,则从末端开始对每个字节进行拷贝。但数据量大时速度慢,将两种方法结合后能够提高拷贝函数性能,代码如下:

void *Memcpy(void *dest, const void *src, size_t count)  
{  
   cout<<"sizeof(dest)是:"<<sizeof(dest)<<endl;
   int bytelen=count/sizeof(dest); /*按CPU位宽拷贝*/
   int slice=count%sizeof(dest); /*剩余的按字节拷贝*/
   unsigned int* d = (unsigned int*)dest;  
    unsigned int* s = (unsigned int*)src;  

 if (((int)dest > ((int)src+count)) || (dest < src))  
    {  
      while (bytelen--)  
        *d++ = *s++;  
      while (slice--)  
        *(char *)d++ = *(char *)s++; 
    }  
 else /* overlap重叠 */  
    {  
    d = (unsigned int*)((unsigned int)dest + count - 4); /*指针位置从末端开始,注意偏置 */  
    s = (unsigned int*)((unsigned int)src + count -4);  
    while (bytelen --)  
        *d-- = *s--;  
 d++;s++;
 char * d1=(char *)d;
 char * s1=(char *)s;
 d1--;s1--;
 while (slice --)  
        *(char *)d1-- = *(char *)s1--; 
    }  
 return dest;  
}  

   资料直通车:Linux内核源码技术学习路线+视频教程内核源码

学习直通车:Linuxc/c++高级开发【直播公开课】

零声白金VIP体验卡:零声白金VIP体验卡(含基础架构/高性能存储/golang/QT/音视频/Linux内核)

对比一下,测试代码如下:

int main(){
 char a[20]="1133224466558877990";
// Memcpy1(a+2,a,5);
// Memcpy2(a+2,a,5);
 Memcpy(a+2,a,5);
 cout<<a<<endl;
 cin.get();
}

运行结果:Memcpy1:1111333466558877990Memcpy2:1111332466558877990Memcpy:1111332466558877990

后两种方法正确,第一种方法拷贝时无法规避内存重叠的bug。

原文作者:wykup

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1117754.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Easyx趣味编程,鼠标消息读取及音频播放(坤坤播放器)

hello大家好&#xff0c;这里是dark flame master&#xff0c;今天给大家带来Easyx图形库最后一节功能实现的介绍&#xff0c;前边介绍了绘制各种图形及键盘交互&#xff0c;文字&#xff0c;图片等操作&#xff0c;今天就可以使写出的程序更加生动且容易操控。一起学习吧&…

选择最佳的项目管理工具:推荐哪一个?

项目管理工具推荐哪个&#xff1f;Zoho Projects项目管理工具为各类团队提供卓越的项目管理解决方案。 1、全面管理各类团队项目 Zoho Projects是一款全面的项目管理工具&#xff0c;具备简化工作流程和提高团队生产力的功能。无论是软件开发与DevOps&#xff0c;还是人力资源与…

Go语言入门心法(十二): GORM映射框架

Go语言入门心法(一): 基础语法 Go语言入门心法(二): 结构体 Go语言入门心法(三): 接口 Go语言入门心法(四): 异常体系 Go语言入门心法(五): 函数 Go语言入门心法(六): HTTP面向客户端|服务端编程 Go语言入门心法(七): 并发与通道 Go语言入门心法(八): mysql驱动安装报错o…

HTTP响应

HTTP响应分为四个部分&#xff1a; 首行&#xff1a;HTTP/1.1&#xff08;首行&#xff09; 200&#xff08;状态码&#xff09; OK&#xff08;状态码描述&#xff09;header&#xff1a;空行&#xff1a;表示header的结束标记body&#xff1a;正文 HTTP状态码&#xff1a;…

想做情感配音解说就用这个软件~

很多视频里的声音都很好听&#xff0c;有的字正腔圆&#xff0c;有的情感真挚&#xff0c;有的激昂慷慨&#xff0c;有的忧伤动人&#xff0c;但你知道吗&#xff1f;这些都不是真人配音的效果&#xff0c;而是配音软件制作合成的效果。一个好的配音可以起到事半功倍的效果。今…

C#中各种循环遍历的功能与应用

在C#编程中&#xff0c;循环遍历是一种重要的技巧&#xff0c;它使我们能够有效地处理集合、数组和其他数据结构。本文将深入探讨C#中常见的循环遍历方式&#xff0c;包括for循环、foreach循环、while循环和do while循环&#xff0c;并给出它们在实际应用中的使用场景、示例和最…

国内外数据保护(灾备、备份、恢复、复制、归档)厂商

做在数据保护领域呆了3年&#xff0c;这里回顾一下经常接触、对比的国内外服务提供商。 国内做数据保护一般会和国外的这几家进行对比&#xff1a; commvault&#xff0c;一般简称为CV Commvault 是一家美国上市数据保护和数据管理软件公司&#xff0c;总部位于新泽西州廷顿…

STM32F4x之中断一

一、中断简介 中断概念&#xff1a;程序在运行过程中发生了外部或内部事件时&#xff0c;导致中断了正在执行的程序&#xff0c;让CPU转到外部或内部事件中去执行。 中断的作用&#xff1a;大量节约CPU资源&#xff0c;提高程序的效率&#xff0c;即避免重要事件被错过。 中断…

深度强化学习 第 5 章 SARSA 算法

上一章介绍了 Q 学习的表格形式和神经网络形式&#xff08;即 DQN&#xff09;。 TD 算法是一大类算法的总称。上一章用的 Q 学习是一种 TD 算法&#xff0c; Q 学习的目的是学习最优动作价值函数 Q ⋆ Q_⋆ Q⋆​ 本章介绍 SARSA&#xff0c;它也是一种 TD 算法&#xff0c; S…

vue3 + fastapi 实现选择目录所有文件自定义上传到服务器

文章目录 ⭐前言&#x1f496; 技术栈选择 ⭐前端页面搭建&#x1f496; 调整请求content-type传递formData ⭐后端接口实现&#x1f496; swagger文档测试接口 ⭐前后端实现效果&#x1f496; 上传单个文件&#x1f496; 上传目录文件 ⭐总结⭐结束 ⭐前言 大家好&#xff0c…

UE5场景逐渐变亮问题

1、显示 -- 关闭眼部适应 2、项目设置 -- 关闭自动曝光 参考&#xff1a; 虚幻5/UE5 场景亮度逐渐变亮完美解决方法 - 哔哩哔哩

2024免费的苹果电脑杀毒软件cleanmymac X

苹果电脑怎么杀毒&#xff1f;这个问题自从苹果电脑变得越来越普及&#xff0c;苹果电脑的安全性问题也逐渐成为我们关注的焦点。虽然苹果电脑的安全性相对较高&#xff0c;但仍然存在着一些潜在的威胁&#xff0c;比如流氓软件窥探隐私和恶意软件等。那么&#xff0c;苹果电脑…

mac苹果电脑使用耳机听不到声音

大家在使用耳机收听音乐时候&#xff1f;是否经常遇到声音和音频播放问题的情况。这里小编为大家带来了三种不同的方法&#xff0c;帮助大家解决耳机在macOS系统电脑上怎么听不到任何声音的教程。如果大家对这篇文章感兴趣&#xff0c;那就来看下面的具体步骤吧。 方法一、检查…

平行进口美规,加版奔驰S500 S580更换主机,汉化导航,语音交互等功能

平行进口美规&#xff0c;加版奔驰S500 S580更换中规主机后&#xff0c;有中国地图导航&#xff0c;AR实景画面&#xff0c;中文你好奔驰&#xff0c;汉化摄氏度&#xff0c;激活自动变道&#xff0c;增强型抬头显示还可以实现箭头指示功能&#xff0c;原车带流星雨大灯还可以实…

人均瑞数系列,瑞数 6 代 JS 逆向分析

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;不提供完整代码&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 本文章未…

“时尚设计 时尚原创”首届广州(三元里)时尚设计大赛正式起航

10月18日上午&#xff0c;由广州市商务局、广州市工业和信息化局、白云区人民政府指导&#xff0c;白云区科技工业商务和信息化局、白云区三元里街道办事处主办&#xff0c;广东省皮具商会、三元里街工商业联合会承办&#xff0c;白云世界皮具贸易中心作为执行单位的首届广州(三…

免费高清壁纸下载(静态和动态壁纸)

一、网址下载&#xff08;静态壁纸&#xff09; 高清图片直接另存为就可以了。然后在电脑空白处右键——个性化设置即可替换壁纸。 ①网址&#xff1a;https://www.hippopx.com ②极简壁纸&#xff1a;https://bz.zzzmh.cn/index ③彼岸图网&#xff1a;http://pic.netbian…

大模型基础——大模型范式

大模型背后的范式 整个预训练语言模型的使用范式&#xff1a; 对于预训练模型&#xff0c;最核心的要素是从无标注的数据中去学习&#xff0c;通过自监督的一些任务去做预训练&#xff0c;得到丰富的知识。在具体的应用中&#xff0c;会引入一些任务相关的数据&#xff0c;去调…

Leetcode—2525.根据规则将箱子分类【简单】

2023每日刷题&#xff08;五&#xff09; Leetcode—2525.根据规则将箱子分类 实现代码 char * categorizeBox(int length, int width, int height, int mass){long long volume;long long len (long long)length;long long wid (long long)width;long long heig (long lo…

十八、字符串(2)

本章概要 格式化输出 printf()Systen.out.format()Formatter 类格式化修饰符Formatter 转换String.format() 一个十六进制转储&#xff08;dump&#xff09;工具 格式化输出 在长久的等待之后&#xff0c;Java SE5 终于推出了 C 语言中 printf() 风格的格式化输出这一功能…