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( ...
随机推荐
- laravel Route::resource() 资源路由
格式: Route::resource('/order', 'OrderController', ['as' => 'admin']); 框架自动创建路由及其对应控制器中的方法: 请求方式 路由 ...
- Abrt
https://abrt.readthedocs.io/en/latest/faq.html#unpackaged
- 一、基础篇--1.1Java基础-面向对象的特征
面向对象的特征 封装.继承和多态 https://blog.csdn.net/jianyuerensheng/article/details/51602015 封装: 定义:封装就是将数据或函数等集合 ...
- 二、Jmter查看结果数只能显示有限的数据,查看全部数据
1.打开jmeter安装目录,找到bin目录下jmeter.properties文件 2.搜索:view.results.tree.max_size=10485760 3.将#号去掉,重启jmeter
- mysql查询时特殊字符转译
commons.lang String value = StringEscapeUtils.escapeSql(searchRequest.getSearchValue());
- Jmeter之插件安装
在实际工作中,会用到一些额外的jmeter插件,现在描述其插件的安装. 一.下载plugins-manager.jar 在官网中下载plugins-manger.jar,方便后续其他插件的安装,下载地 ...
- Unity3D 协程 Coroutine
协程(Coroutine)的概念存在于很多编程语言,例如Lua.ruby等.而由于Unity3D是单线程的,因此它同样实现了协程机制来实现一些类似于多线程的功能,但是要明确一点协程不是进程或线程,其执 ...
- Java ——补充:构造方法 super()与构造方法 无参 有参构造方法 this()与构造方法
参考文章: https://blog.csdn.net/qq_33322074/article/details/86030836 https://blog.csdn.net/HD243608836/a ...
- 【BASIS系列】SAP Basis系统管理中重置用户缓冲哪些需要注意
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[BASIS系列]SAP Basis系统管理中重 ...
- 求方程x1+x2+x3=15的整数解的数目
求方程x1+x2+x3=15的整数解的数目要求0≤x1≤5,0≤x2≤6,0≤x3≤7.解:令N为全体非负整数解(x1,x2,x3),A1为其中x1≥6的解:y1=x1-6≥0的解:A2为其中x2≥7 ...