兼顾内存和速度的C语言代码优化的方法

💡 原文中文,约14800字,阅读约需36分钟。
📝

内容提要

本文介绍兼顾内存与速度的C语言优化方法:先用性能工具定位热点代码,优先优化循环;多用无符号整型,避免除法与取余,改用移位、乘法或if;少用全局变量,用局部变量缓存指针链;简化条件判断,用switch或查找表替代长if链;循环宜递减计数、展开并尽早break;函数参数控制在四个以内,常用小函数用inline或查找表;浮点运算用float、以乘法代除法;最后开启编译器优化选项。

🔎

延伸解读

优化前先定位热点

文章强调,优化不能盲目开始,而应先用性能工具找出程序中最慢或最耗内存的部分。作者使用过Visual C++的profiler和英特尔的Vtune,并指出内部或嵌套循环以及调用第三方库的方法通常是性能瓶颈。这意味着读者在尝试文中具体技巧前,应先确认热点代码,否则可能优化了不重要的部分,反而增加代码复杂度。

内存与速度的权衡

文章开篇即指出,优化往往需要增加代码量来换取速度,但这会提高复杂性和降低可读性,在内存受限的移动设备上尤其不可接受。因此作者的目标是兼顾内存使用和执行速度。读者应注意,文中许多技巧(如循环展开、内联函数、查找表)都以增加代码体积为代价,是否采用需结合具体平台的内存约束来判断。

整数与除法的代价

文章详细说明,32位除法在标准处理器上需要20至140次循环操作,应尽量避免。若确定操作数非负,使用unsigned int比int效率更高;除数为2的幂次时编译器可用移位替代除法;同时需要商和余数时,写在一起可让编译器一次除法返回两个结果。这些方法在热点循环中效果明显,但需注意无符号和有符号语义差异,避免改变程序逻辑。

循环与函数调用的优化

文章建议循环采用递减计数到零、尽早break、适当展开,并合并重复循环以减少开销。函数方面,参数尽量少于四个以避免栈传递,常用小函数可用inline或查找表替代。但作者也提醒,循环展开和内联会增加代码体积,查找表会降低精确度,因此这些技巧更适合热点路径,而非全盘套用。

❓

Q&A

C语言代码优化时,应该优先优化哪些部分?

应优先优化程序中运行最频繁的部分,尤其是被内部循环不断调用的方法。可以使用性能工具(如Visual C++的profiler或英特尔的Vtune)来定位执行缓慢或消耗内存最多的代码。

在C语言中,如何优化除法和取余运算?

除法运算消耗大,应尽量避免。可以用乘法替代除法,例如若b为正且b*c为整数,则(a/b)>c可改写为a>(c*b)。同时需要商和余数时,将除法和取余写在一起让编译器一次调用返回两者。若除数是2的幂次,编译器会用移位操作。取模操作有时可用if语句替代,如用if(++count>=60) count=0;代替count%60。

为什么在C语言中要少用全局变量?如何优化?

全局变量不会位于寄存器中,编译器不能将其值缓存在寄存器,导致额外的读取和存储。在重要循环中应避免使用全局变量。优化方法是将全局变量的值拷贝到局部变量,在局部变量上操作,最后再写回全局变量。

如何优化C语言中的循环以提高执行速度?

可以采用递减计数循环(如for(i=n; i!=0; i--)),使用简单的终止条件;合并循环(但若循环内工作多,分开可能更快);展开循环以减少循环开销;尽早断开循环(如找到目标后立即break)。

C语言函数设计时,参数数量有什么优化建议?

尽量保证函数使用少于四个参数,这样参数可通过寄存器传递,避免使用栈。如果参数多于四个,后续参数会存储在栈上,增加存储和读取消耗。可通过指针传递结构体、将参数放入结构体并用指针传入、少用long和double等占用两个字的类型、避免变参等方法来减少参数传递消耗。

在C语言中,如何优化浮点运算?

使用float代替double以节省内存和寄存器;用乘法代替除法(如x=x*(1.0/3.0));避免使用sin、exp、log等先验函数;简化浮点表达式;若精度允许,考虑使用定点运算。

🏷️

标签

➡️

继续阅读