C语言性能优化
- 1、数据类型
1)如果确定整数非负,应直接使用unsigned int,处理器处理无符号unsigned 整形数的效率远远高于有符号signed整形数
2)float可以用int替代,如果需要结果精确到小数点后n位,可以将其乘以n*10,结果尽可能晚的把它转换为浮点型数字
3)局部变量尽可能的不使用char和short类型。对于char和short类型,编译器需要在每次赋值的时候将局部变量减少到8或者16位,是通过寄存器左移24或者16位,然后根据有无符号标志右移相同的位数实现,这会消耗两次计算机指令操作
- 2、乘除法和取余数
1)在标准处理器中,对于分子和分母,一个32位的除法需要使用20至140次循环操作。除法函数消耗的时间包括一个常量时间加上每一位除法消耗的时间:
Time (numerator / denominator) = C0 + C1* log2 (numerator / denominator)
= C0 + C1 * (log2 (numerator) - log2 (denominator))
对于ARM处理器,这个版本需要20+4.3N次循环
2)除数是2的幂次,使用移位操作来执行除法,并尽可能的设置除数为2的幂次
3)除法可以替换成乘法:(a/b)>c可以改写为a>(cb),转换为乘法时需注意是否会溢出
4)乘法可以修改为移位实现:a=a9 替换为a=(a<<3)+a
5)连除可以由乘法代替,但有可能在算乘积时会溢出,使用时要特别注意:m = i / j / k替换为 m = i / (j * k)
6)取Mod替换方法:
a.取8余数 mod%8 等价转换 mod & 7,通常,只要求是求2n方的余数,均可使用位操作的方法来代替
b.用条件判断替换:
int func_mod(int cnt)
{
return (cnt++ % 20);
}
替换为:
int func_mod(int cnt)
{
if (count++ >= 20)
{
cnt = 0;
}
return cnt;
}
- 3、使用数组
//使用数组下标获取字符数组的值
static char *str="hello";
... ...
chr = str[index];
- 4、全局变量
使用全局变量时,需要额外的读取和存储(调用函数中加载,并存储全局变量的值),在重要的循环中不建议使用全局变量 - 5、指针
1)尽可能的使用引用值的方式传递结构数据,也就是说使用指针,否则传递的数据会被拷贝到栈中,从而降低程序的性能
2)指针链使用局部变量赋值替换,减少层级
p->pst->a = 0;
p->pst->b = 0;
p->pst->c = 0;
//代码在每次操作时必须重复调用p->pst
pt = p->pst;
pt->a = 0;
pt->b = 0;
pt->c = 0;
- 6、条件判断
1)使用switch替代if else
switch…case会生成一份大小(表项数)为最大case常量+1的跳表,程序首先判断switch变量是否大于最大case 常量,若大于,则跳到default分支处理;否则取得索引号为switch变量大小的跳表项的地址(即跳表的起始地址+表项大小*索引号),程序接着跳到此地址执行
2)在if(xxx1>XXX1 && xxx2=XXX2)多个条件判断中,确保AND表达式的第一部分最快或最早得到结果,这样第二部分便有可能不需要执行
3)在必须使用if…else…语句,将最可能执行的放在最前面 - 7、使用增量和减量操作符
增量符语句比赋值语句更快,原因在于对大多数CPU来说,对内存字的增、减量操作不必明显地使用取内存和写内存的指令 - 8、把频繁使用的指针型参数拷贝到本地变量
避免在函数中频繁使用指针型参数指向的值。因为编译器不知道指针之间是否存在冲突,所以指针型参数往往不能被编译器优化