【c语言经典面试题】memcpy函数有没有更高效的拷贝实现方法?
我相信大部分初中级c程序员在面试的过程中,可能都被问过关于memcpy函数的问题,甚至需要手撕memcpy。本文从另一个角度带你领悟一下memcpy的面试题,你可以看看是否能接得住?
1 写在前面2 源码实现2.1 函数申明2.2 简单的功能实现2.3 满足大数据量拷贝的功能实现3 源码测试4 小小总结5 更多分享
1 写在前面假如你遇到下面的面试题,你会怎么做?题目大意如下:
请参考标准c库对memcpy的申明定义,使用c语言的语法实现其基本功能,并尽量保证它在拷贝大数据(kk级别)的时候,有比较好的性能表现。
2 源码实现2.1 函数申明通过查看man帮助,我们可以知道memcpy函数的功能及其简要申明。
name memcpy - copy memory area synopsis #include英文翻译过来就是说,memcpy实现的就是内存拷贝,其是按字节进行拷贝,同时还可能会存在内存区域重合的情况。
2.2 简单的功能实现根据功能需求,以下是我的一个简单实现源码,仅供参考:
char *my_memcpy(char* dest, const char *src, size_t len) { assert(dest && src && (len > 0)); if (dest == src) { ; } else { char *p = dest; size_t i; for (i = 0; i < len; i++) { *p++ = *src++; } } return dest; }但是,这段代码的缺陷也比较明显,但数据量过大的时,即len很大时,整一个拷贝耗时将会非常不理想。那么如果考虑性能问题,又该如何实现它呢?
2.3 满足大数据量拷贝的功能实现下面给出一个参考实现:
/* nonzero if either x or y is not aligned on a long boundary. */ #define unaligned(x, y) \\ (((long)x & (sizeof(long) - 1)) | ((long)y & (sizeof(long) - 1))) /* how many bytes are copied each iteration of the 4x unrolled loop. */ #define bigblocksize (sizeof(long) << 2) /* how many bytes are copied each iteration of the word copy loop. */ #define littleblocksize (sizeof(long)) /* threshhold for punting to the byte copier. */ #define too_small(len) ((len) 0)); char *dest = dest0; const char *src = src0; long *aligned_dest; const long *aligned_src; /* if the size is small, or either src or dst is unaligned, then punt into the byte copy loop. this should be rare. */ if (!too_small(len0) && !unaligned(src, dest)) { aligned_dest = (long *)dest; aligned_src = (long *)src; /* copy 4x long words at a time if possible. */ while (len0 >= bigblocksize) { *aligned_dest++ = *aligned_src++; *aligned_dest++ = *aligned_src++; *aligned_dest++ = *aligned_src++; *aligned_dest++ = *aligned_src++; len0 -= bigblocksize; } /* copy one long word at a time if possible. */ while (len0 >= littleblocksize) { *aligned_dest++ = *aligned_src++; len0 -= littleblocksize; } /* pick up any residual with a byte copier. */ dest = (char *)aligned_dest; src = (char *)aligned_src; } while (len0--) *dest++ = *src++; return dest0; } 我们可以看到,里面做了对齐的判断,还有数据量长度的判断;通过充分利用机器的操作性能,从而提升memcpy拷贝的效率。
3 源码测试**简单的测试代码如下,目的就是测试在拷贝 **1kb数据和10mb数据 时,标准c的memcpy、自定义的memcpy_normal、以及自定义的memcpy_super直接的性能差异:
#include #include static void get_rand_bytes(unsigned char *data, int len) { int a; int i; srand((unsigned)time(null)); //种下随机种子 for (i = 0; i < len; i++) { data[i] = rand() % 255; //取随机数,并保证数在0-255之间 //printf(%02x , data[i]); } } static int get_cur_time_us(void) { struct timeval tv; gettimeofday(&tv, null); //使用gettimeofday获取当前系统时间 return (tv.tv_sec * 1000 * 1000 + tv.tv_usec); //利用struct timeval结构体将时间转换为ms } #define array_size(n) sizeof(n) / sizeof(n[0]) int main(void) { int size_list[] = { 1024 * 1024 * 10, // 10mb 1024 * 1024 * 1, // 1mb 1024 * 100, // 100kb 1024 * 10, // 10kb 1024 * 1, // 1kb }; char *data1; char *data2; int t1; int t2; int i = 0; data1 = (char *)malloc(size_list[0]); data2 = (char *)malloc(size_list[0]); get_rand_bytes(data1, size_list[0]); for (i = 0; i < array_size(size_list); i++) { t1 = get_cur_time_us(); memcpy(data2, data1, size_list[i]); t2 = get_cur_time_us(); printf(copy %d bytes, memcpy_stdc waste time %dus\\n, size_list[i], t2 - t1); t1 = get_cur_time_us(); my_memcopy_normal(data2, data1, size_list[i]); t2 = get_cur_time_us(); printf(copy %d bytes, memcpy_normal waste time %dus\\n, size_list[i], t2 - t1); t1 = get_cur_time_us(); my_memcopy_super(data2, data1, size_list[i]); t2 = get_cur_time_us(); printf(copy %d bytes, memcpy_super waste time %dus\\n\\n, size_list[i], t2 - t1); } free(data1); free(data2); return 0; } 简单执行编译后,运行小程序的结果:
从运行结果上看:
**拷贝数据量比较小时,拷贝效率排行: **normal < super < stdc**拷贝数据量比较大时,拷贝效率排行: **normal < stdc < super4 小小总结memcpy的源码实现,核心就是内存拷贝,要想提升拷贝的效率,还得充分利用机器的运算性能,比如考虑对齐问题。
综合来看,标准c库实现的memcpy在大部分的场景下都可以有一个比较好的性能表现,这一点是值得称赞的。
5 更多分享[架构师李肯]
架构师李肯 ( 全网同名 ),一个专注于嵌入式iot领域的架构师。有着近10年的嵌入式一线开发经验,深耕iot领域多年,熟知iot领域的业务发展,深度掌握iot领域的相关技术栈,包括但不限于主流rtos内核的实现及其移植、硬件驱动移植开发、网络通讯协议开发、编译构建原理及其实现、底层汇编及编译原理、编译优化及代码重构、主流iot云平台的对接、嵌入式iot系统的架构设计等等。拥有多项iot领域的发明专利,热衷于技术分享,有多年撰写技术博客的经验积累,连续多月获得rt-thread官方技术社区原创技术博文优秀奖,荣获[csdn博客专家]、[csdn物联网领域优质创作者]、[2021年度csdn&rt-thread技术社区之星]、[2022年rt-thread全球技术大会讲师]、[rt-thread官方嵌入式开源社区认证专家]、[rt-thread 2021年度论坛之星top4]、[华为云云享专家(嵌入式物联网架构设计师)]等荣誉。坚信【知识改变命运,技术改变世界】!
电气常用的测量方法
液晶屏背光LED驱动电路图
南桥芯片
MS8829无刷直流马达特点及应用
开发工具Visual Studio 2017的安装和使用图文教程
【性能优化】memcpy函数有没有更高效的拷贝实现方法?
为什么压敏电阻具有非线性伏安特性
仅两周,苹果 iPhone 12 成 10 月全球销量最高 5G 智能手机
中微子可以自由的穿梭在任何空间内 运动起来可以接近光速
嵌入式芯片RISC-V未来前景如何
纳秒激光焊接机如何实现高精度焊接
2019年第一季度全球智能手表调查报告公布 华米科技AMAZFIT成功跻身全球前五
中国反侵权假冒联盟称苹果公司应自觉履行禁令裁定
小米8与小米MIX2S获内测版推送 支持960帧慢动作拍摄
MEN PowerPC单片机提供嵌入式通信功能
EMC防护中的滤波电容、旁路电容和去耦电容正确理解
健身房镜面显示屏再升级,让健身运动更为智能
新型微控制器在防窃电及计量电表中的应用
电连接器、航空插头、接插件的常用术语
温度补偿晶体振荡器技术术语简介