龙空技术网

C语言程序员应重视效率,memcpy函数这么高效,使用了什么技巧?

IT刘小虎 430

前言:

此时姐妹们对“c语言memmove”可能比较看重,兄弟们都想要剖析一些“c语言memmove”的相关文章。那么小编也在网摘上收集了一些有关“c语言memmove””的相关文章,希望兄弟们能喜欢,咱们一起来学习一下吧!

在C语言程序开发中,常常需要将 N 个字节从源内存段 pSrc 拷贝到目的内存段 pDest。稍稍有些经验的程序员一般都会调用C语言标准库函数 memcpy() 或者 memmove(),事实上,大多数程序员都会调用这两个库函数实现需求。

为什么逐项赋值没有memcpy() 快?

为什么逐项赋值没有memcpy() 快?

C语言程序员都是乐于思考的,在调用 memcpy() 函数实现内存拷贝时,往往会思考 memcpy() 函数的实现方式。在一些程序员看来,memcpy() 无非就是下面这样的逐项拷贝:

int i;for(i=0; i<N; i++) *pDest++ = *pSrc++;

考虑到 memcpy() 函数可以接收任意类型的源内存段指针和目标内存段指针,用C语言来描述就是 memcpy() 函数接收的源内存段指针和目标内存段指针都是 void * 指针,因此可能还要多一步指针类型转换:

void my_memcpy(void* dst, void* src, unsigned int bytes){ unsigned char* b_dst = (unsigned char*)dst; unsigned char* b_src = (unsigned char*)src; for (int i = 0; i < bytes; ++i) *b_dst++ = *b_src++;}

可能还要多一步指针类型转换

这里转换为 unsigned char* 指针只仅作为示例,读者当然可以将其转换为其他类型指针。

乐于动手的C语言程序员一定自己尝试实现过自己的 memcpy() 函数,如果读者尝试过自己的实现,在性能测试中一定能够发现,上述实现的效率并没有 memcpy() 库函数的效率高,这是为什么呢?

memcpy() 函数使用的技巧

既然逐字节赋值拷贝的 my_memcpy() 效率比不上 memcpy() 函数,那么 memcpy() 函数一定使用了某些技巧,到底是什么技巧呢?

前文介绍的 my_memcpy() 实现是将接收到的指针转换成 char * 指针,逐字节拷贝的。但是 memcpy() 函数一般不使用字节指针,而是使用字指针。

看过我之前文章的读者应该明白,CPU 在处理数据时,如果数据严格按照数据总线宽度对齐,那么CPU才能最大效率处理数据。

事实上,memcpy() 函数的实现通常使用 SIMD 指令编写,这使得它能够一次操作 128 位数据。关于 SIMD 指令,以后有机会再讨论。现在读者只需知道,memcpy() 函数一次可以拷贝 16 字节的数据就可以了,这比一次只拷贝 1 字节的数据效率高多了。

改进 my_memcpy() 函数,提升效率的方向

C语言程序员在实际拷贝数据时,要拷贝的数据长度不一定是 16 字节的整数倍,所以 memcpy() 的实现要比 my_memcpy() 的实现复杂得多。

memcpy() 的实现要比 my_memcpy() 的实现复杂得多

my_memcpy() 的第一个改进是在内存时按照本机字宽度( 32位机器一般是4字节,64位机器一般是8字节)对齐要拷贝的数据,并且使用字指针而不是字节指针拷贝数据,相关的C语言代码如下:

void aligned_memory_copy(void* dst, void* src, unsigned int bytes){ unsigned char* b_dst = (unsigned char*)dst; unsigned char* b_src = (unsigned char*)src; // Copy bytes to align source pointer while ((b_src & 0x3) != 0) { *b_dst++ = *b_src++; bytes--; } unsigned int* w_dst = (unsigned int*)b_dst; unsigned int* w_src = (unsigned int*)b_src; while (bytes >= 4) { *w_dst++ = *w_src++; bytes -= 4; } // Copy trailing bytes if (bytes > 0) { b_dst = (unsigned char*)w_dst; b_src = (unsigned char*)w_src; while (bytes > 0) { *b_dst++ = *b_src++; bytes--; } }}

使用字指针而不是字节指针拷贝数据

源内存段指针或者目标内存段指针是否正确对齐,在不同架构的机器上将执行不同的操作。例如,在 XScale 处理器上,通过对齐目标内存段指针,在实际性能测试中,我获得了更高的内存拷贝效率。

若想进一步提升内存拷贝的效率,可以将一些C语言代码中的循环展开,便于提高 CPU 缓存的命中率。不过这种方式带来的效率提升会因体系架构的不同而不同,因为 CPU 加载和存储数据的方式可能是不同的。

还有一种提升效率的方式,即手动编写 CPU 加载和存储指令,以控制数据吞吐量。不过这种方式需要借助汇编指令实现,C语言暂时还没有能力实现这样的精细操作。

小结

容易看出,在C语言程序开发中,简单的内存拷贝也并不简单,我们有着相当多的优化空间。C语言程序的灵魂之一就是高效率,而C语言本身提供的都是最基础的操作,因此它是一种相当重视设计的程序语言,作为C语言程序员,我们在设计某个方法时,应该总是想清楚如何才能写出更高效的程序。

点个关注,再点个赞再走吧

欢迎在评论区一起讨论,质疑。文章都是手打原创,每天最浅显的介绍C语言、linux等嵌入式开发,喜欢我的文章就关注一波吧,可以看到最新更新和之前的文章哦。

未经许可,禁止转载。

标签: #c语言memmove #c语言memmove函数 #c memcpy函数用法 #c中memcpy函数用法