memcpy函数的用法以及实现一个memcpy函数
- memcpy的用法
在项目中经常用到memcpy来实现内存的拷贝工作,如下代码片段
memcpy( pData, m_pSaveData_C, iSize * sizeof( unsigned short ) );
memcpy的函数原型为:
void * memcpy ( void * destination, const void * source, size_t num );
memcpy函数的功能是从源内存地址的起始位置开始拷贝若干个字节到目标内存地址中,即从源source中拷贝num个字节到目标destin中。
示例代码
int main()
{
vector<int> vec;
vector<int> vec1;
vec.push_back(10);
vec.push_back(100);
vec1.resize(vec.size());
memcpy(vec1.data(),vec.data(),vec.size() * sizeof(int));
for (vector<int>::iterator it = vec1.begin();it != vec1.end();it++)
{
cout << *it;
}
char myname[] = "Pierre dee Fermat";
memcpy(person.name,myname,strlen(myname) + 1);
person.age = 46;
cout << person.name << " " << person.age << endl;
cout << "sizeof(person) = " << sizeof(person) << endl;
memcpy(&person_copy,&person, sizeof(person));
cout << person_copy.name << " " << person_copy.age << endl;
return 0;
}
注意:是按照字节拷贝,这个刚开始的时候我总是用错。刚开始的时候,memcpy(vec1.data(),vec.data(),vec.size() * sizeof(int));我总是写成memcpy(vec1.data(),vec.data(),vec.size());忘记加后面的sizeof(int)。
另外这个函数不能处理内存重叠的情况,当source和destin所指的内存区域重叠,那么这个函数并不能够确保source所在重叠区域在拷贝之前不被覆盖。而使用memmove可以用来处理重叠区域。函数返回指向destin的指针。
- 实现一个memcpy
1.按字节(Byte)拷贝实现的memcpy
/*
按照字节(Byte)拷贝实现的my_memcpy
*/
void* my_memcpy(void* dst,const void* src,int n)
{
if (dst == NULL || src == NULL || n <= 0)
{
//void* 一定要有返回值 void可以没有返回值 void*和void不相同
return NULL;
}
char* pdst = (char *)dst;
char* psrc = (char *)src;
if (psrc < pdst && pdst < psrc + n)
{
pdst = pdst + n - 1;
psrc = psrc + n - 1;
while (n--)
{
*pdst = *psrc;
pdst--;
psrc--;
}
}
else
{
while (n--)
{
*pdst = *psrc;
pdst++;
psrc++;
}
}
return dst;
}
上面的按字节拷贝的过程中考虑了拷贝覆盖,连续的一段空间存放数据是从低地址到高地址进行存放。先从源地址中取出数据,然后写入到目的地址空间中。目的空间的起始地址如果在源空间之内就会出现内存覆盖的情况。
如下图:

这种情况一定要先从尾部拷贝,避免数据覆盖,不过这种情况也会破坏src空间数据,虽然在src前面加了const关键字,表示这部分空间是只读的,但是编译器并不会报错。
测试代码:
int main()
{
/* 测试内存重叠的情况 */
char str1[] = { "abcdefg" };
my_memcpy(str1 + 2,str1,sizeof(char) * 4);
//memmove(str1 + 2, str1, sizeof(char) * 4);
cout << str1 << endl;
return 0;
}
2.按照4字节拷贝
上面的拷贝是一次拷贝一个字节,现在考虑一次拷贝四个字节,充分的利用总线位宽。
/*
按4字节拷贝
*/
void* my_memcpy1(void* dst,void* src,int n)
{
if (dst == NULL || src == NULL || n <= 0)
{
//void* 一定要有返回值 void可以没有返回值 void*和void不相同
return NULL;
}
int* pdst = (int*)dst;
int* psrc = (int*)src;
char* temp1 = NULL;
char* temp2 = NULL;
int c1 = n / 4;
int c2 = n % 4;
if (psrc < pdst && pdst < psrc + n)
{
temp1 = (char*)pdst + n - 1;
temp2 = (char*)psrc + n - 1;
while (n--)
{
*temp1 = *temp2;
temp2--;
temp1--;
}
}
else
{
while (c1--)
{
*pdst= *psrc;
pdst++;
psrc++;
}
temp1 = (char*)pdst;
temp2 = (char*)psrc;
while (c2--)
{
*temp1= *temp2;
temp1++;
temp2++;
}
}
return dst;
}
这里还是考虑了写覆盖的代码,但是写覆盖的代码和之前一个字节一个字节拷贝的实现方式是一样的。
- 参考资料
1 https://www.cnblogs.com/chuanfengzhang/p/8447251.html 《实现memcpy()函数及过程总结》
2 https://www.xuebuyuan.com/778923.html 《闲着没事测了一下memcpy》
3 https://www.zhihu.com/question/35172305 《怎样写出一个更快的 memset/memcpy?》
memcpy函数的用法以及实现一个memcpy函数的更多相关文章
- memset函数及其用法,C语言memset函数详解
在前面不止一次说过,定义变量时一定要进行初始化,尤其是数组和结构体这种占用内存大的数据结构.在使用数组的时候经常因为没有初始化而产生“烫烫烫烫烫烫”这样的野值,俗称“乱码”. 每种类型的变量都有各自的 ...
- np.random.random()函数 参数用法以及numpy.random系列函数大全
原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/9751471.html 1.np.random.random()函数参数 np.random.r ...
- 【转】np.random.random()函数 参数用法以及numpy.random系列函数大全
转自:https://www.cnblogs.com/DOMLX/p/9751471.html 1.np.random.random()函数参数 np.random.random((1000, 20) ...
- MySQL CAST与CONVERT 函数的用法
MySQL CAST与CONVERT 函数的用法 产生另一个类型的值 MySQL 的CAST()和CONVERT()函数可用来获取一个类型的值,并产生另一个类型的值. 两者具体的语法如下:1 CAS ...
- arguments.callee 调用函数自身用法----JSON.parse()和JSON.stringify()前端js数据转换json格式
arguments.callee 调用函数自身用法 arguments.callee 在哪一个函数中运行,它就代表哪个函数. 一般用在匿名函数中. 在匿名函数中有时会需要自己调用自己,但是由于是匿名函 ...
- SQL decode 函数的用法
decode 函数基本语法: decode(字段|表达式,条件1,结果1,条件2,结果2,...,条件n,结果n,缺省值): --缺省值可以省略 表示如果 字段|表达式 等于 条件1 时,DECODE ...
- python--函数式编程 (高阶函数(map , reduce ,filter,sorted),匿名函数(lambda))
1.1函数式编程 面向过程编程:我们通过把大段代码拆成函数,通过一层一层的函数,可以把复杂的任务分解成简单的任务,这种一步一步的分解可以称之为面向过程的程序设计.函数就是面向过程的程序设计的基本单元. ...
- (60)Wangdao.com第十天_JavaScript 函数_作用域_闭包_IIFE_回调函数_eval
函数 实现特定功能的 n 条语句封装体. 1. 创建一个函数对象 var myFunc = new Function(); // typeof myFunc 将会打印 function ...
- Delphi另一个多线程函数:BeginThread用法
Delphi另一个多线程函数:BeginThread━━━━━━━━━━━━━━━━━━━━━━━━━━ Delphi也提供了一个相同功能的类似函数:function BeginThread( ...
随机推荐
- 微信小程序 API 网络(ajax)
网络 API 类似于 ajax 向服务器请求网络地址,唯一不同的是这个请求有很多的规则,且必须向服务器上请求,不能在本地请求 网络 发送请求: wx.request() 发起https网络请求 参数: ...
- Openstack 实现技术分解 (2) 虚拟机初始化工具 — Cloud-Init & metadata & userdata
目录 目录 前文列表 扩展阅读 系统环境 前言 Cloud-init Cloud-init 的配置文件 metadata userdata metadata 和 userdata 的区别 metada ...
- 编写Python脚本把sqlAlchemy对象转换成dict的教程
编写Python脚本把sqlAlchemy对象转换成dict的教程 在用sqlAlchemy写web应用的时候,经常会用json进行通信,跟json最接近的对象就是dict,有时候操作dict也会比操 ...
- 封装一个windows转发端口的脚本
使用方法: 1.打开文本编辑工具如(Notepad++) 2.新建文件 3.注意:修改文本的编码字符集为:gb2312 4.将下面代码 复制入文件 5.保存文件名为:transmit.bat 6.双击 ...
- itchat初步解读登录(转)
原文:https://blog.csdn.net/coder_pig/article/details/81357810 itchat的登录采取的是通过itchat.auto_login()这个函数来完 ...
- Vue 渲染函数
Vue 推荐在绝大多数情况下使用模板来创建你的 HTML.然而在一些场景中,你真的需要 JavaScript 的完全编程的能力.这时你可以用渲染函数,它比模板更接近编译器. 一 项目结构 二 App组 ...
- 第五周课程总结&实验报告(三)
实验三 String类的应用 实验目的 掌握类String类的使用: 学会使用JDK帮助文档: 实验内容 1.已知字符串:"this is a test of java".按要求执 ...
- Mysql函数----控制流函数介绍
MySQL有4个函数用来进行条件操作的,可以实现SQL的条件逻辑,允许开发者将一些应用程序业务逻辑转换到数据库后台. MySQL控制流函数: 1.CASE WHEN[test1] THEN [re ...
- 使用extract-text-webpack-plugin插件后报错
如果你使用的webpack是4+版本,那么尝试运行npm install extract-text-webpack-plugin@next ,即可解决问题 然而最好的解决办法是在webpack4+的版 ...
- [ARC101E]Ribbons on Tree(容斥,dp)
Description 给定一棵有 \(n\) 个节点的树,满足 \(n\) 为偶数.初始时,每条边都为白色. 现在请你将这些点两两配对成 \(\frac{n}{2}\) 个无序点对.每个点对之间的的 ...