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( ...
随机推荐
- YV12和NV12格式
害怕搞忘 直接保存图片
- kafka操作命令
kafka启动 bin/kafka-server-start.sh -daemon config/server.properties 创建topic bin/kafka-topics.sh -zook ...
- nw.js node-webkit基本程序结构与配置package.json配置说明
(一)基本程序结构 如上图,是一个nw程序的基本组织结构,在根目录下有package.json(程序的配置文件)和index.html(可以是任意名称,应用的启动页面):js/css/resource ...
- vivo 部分链表反转
方法一:使用栈交换需要反转的数字 #include <iostream> #include <stack> #include "list.h" using ...
- Octavia 创建 Listener、Pool、Member、L7policy、L7 rule 与 Health Manager 的实现与分析
目录 文章目录 目录 创建 Listener 创建 Pool 创建 Member CalculateDelta HandleNetworkDeltas AmphoraePostNetworkPlug ...
- 分布式消息队列 Celery 的最佳实践
目录 目录 不使用数据库作为 Broker 不要过分关注任务结果 实现优先级任务 应用 Worker 并发池的动态扩展 应用任务预取数 保持任务的幂等性 应用任务超时限制 善用任务工作流 合理应用 a ...
- 安装docker-下载加速、失败、成功安装
前提:已装VMware虚拟机和Centos系统(具体安装包和过程可以百度) 先看这里:非root身份登录系统需要在下面的命令前加“sudo ”(sudo:代表给权限,用root登录则不需要输入) 一. ...
- python中的各个模块
collection模块:python中的扩展数据模块#namedtuple: 生成可以使用名字来访问元素内容的tuple'''from collections import namedtuplePo ...
- MySQL数据类型之整型
还一个 Decimal 就是这么创建 查看当前数据表 查看tb1得表得所有记录....
- Linux-Maven部署
一.Maven是什么 二.Maven部署 1.环境信息: (1)centos7.3 (2)jdk1.8 (3)maven3.5.3 2.安装jdk (1)下载地址[http://www.oracle. ...