memcpy()函数实现
1.为什么会写memcpy
笔试中遇到过一道笔试题,题目要求实现一个my_memcpy函数。函数原型:void * my_memcpy(void *dst, const void *src, int n); 函数的功能是从源内存地址的起始位置开始拷贝若干个字节到目标内存地址中,即从源src中拷贝n个字节到目标dst中。
之前使用的内存拷贝函数是标准库memcpy函数,拿来就用。当你自己在实现过程中,了解的越多,实现起来就越麻烦。
2.按字节(Byte)拷贝实现的memcpy
- 不考虑写覆盖,简单粗暴:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | void * my_memcpy_byte( void * dst, const void * src, size_t n) { // Copies n bytes from src to dst // Since we cannot dereference a void* ptr, // we first typecast it to a char* ptr // and then do the copying byte by byte, // since a char* ptr references a single byte char * char_dst = ( char *) dst; char * char_src = ( char *) src; for ( int i=0; i<n; i++) { *char_dst++ = *char_src++; } return dst; } |
- 考虑写覆盖:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | void *my_memcpy_byte( void *dst, const void *src, int n) { if (dst == NULL || src == NULL || n <= 0) return NULL; char * pdst = ( char *)dst; char * psrc = ( char *)src; if (pdst > psrc && pdst < psrc + n) { pdst = pdst + n - 1; psrc = psrc + n - 1; while (n--) *pdst-- = *psrc--; } else { while (n--) *pdst++ = *psrc++; } return dst; } //*pdst-- = *psrc--; 查了下运算符优先级(*,--)优先级相同,从右向左结合,psrc--是先使用,后减减 //等价于*pdst = *psrc;psrc--;pdst--; |
3.按4字节拷贝实现的memcpy
void *my_memcpy(void *dst, const void *src, int n)
{
if (dst == NULL || src == NULL || n <= 0)
return NULL;
int * pdst = (int *)dst;
int * psrc = (int *)src;
char *tmp1 = NULL;
char *tmp2 = NULL;
int c1 = n / 4;
int c2 = n % 4;
/*if (pdst > psrc && pdst < psrc + n) 这样判断有问题*/
if (pdst > psrc && pdst < (char *)psrc + n)
{
tmp1 = (char *)pdst + n - 1;
tmp2 = (char *)psrc + n - 1;
while(c2--)
*tmp1-- = *tmp2--;
/*这样有问题,忘记字节偏移
pdst = (int *)tmp1;
psrc = (int *)tmp2;
*/
tmp1++;tmp2++;
pdst = (int *)tmp1;
psrc = (int *)tmp2;
pdst--;psrc--;
while (c1--)
*pdst-- = *psrc--;
}
else
{
while (c1--)
*pdst++ = *psrc++;3536 tmp1 = (char *)pdst;
tmp2 = (char *)psrc;
while (c2--)
*tmp1++ = *tmp2++;
}
return dst;
}
//备注:void *dst, const void *src这两个参数是需要按4字节对齐的,如果本身不是4字节对齐,按4字节拷贝效率也会变低。
这里还是考虑了写覆盖的代码。对比按字节拷贝,拷贝速度是提高不少。
以上是针对笔试过程中写memcpy。
4.如何优化memcpy
高性能的memcpy与很多因数相关,与平台,处理器,编译器,具体拷贝情形等相关。
VS2017中对C库的memcpy进行优化,glibc对memcpy也有优化
5.是否需要考虑内存对齐拷贝?
内存读写效率影响之一:内存对齐
参考:1.浅谈CPU内存访问要求对齐的原因 2.解析内存对齐
如果src,dst的地址是不对齐的,读写效率变低。
通过代码实现不对齐的拷贝,memcpy的实现会变得复杂,反而影响拷贝效率。
这种不对齐情况我们可以预先避免,因为编译器在给我们分配空间时是按照内存对齐进行分配的。
6.根据拷贝数据大小进行优化
1.多次调用memcpy,而每次拷贝数据大小Kb下的小拷贝
这种情况下尽量减少分支预测,代码精简。
2.拷贝Mb的memcpy实现
这种情况影响拷贝效率主要在寻址上。
参考:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
2016-09-14 LVS