针对嵌入式SoC应用的C编程优化
5. 使用本地变量替代全局变量
这是因为全局变量会在整个程序的生命周期里面保留数值。编译器必须认为全局变量可能通过指针被访问。考虑下面的代码:
int g;
void foo()
{
int i;
for (i=0; i100; i++){
fred(i,g);
}
}
理想情况下,g在每次fred循环时被加载一次,并且它的值将被传递到一个寄存器里面给fred函数使用。但是,编译器不知道fred是否会修改g 的值。如果fred不会修改g的值,你应该像下面一样,使用本地变量。这样做可以避免每次调用fred函数时加载g到一个寄存器里面。
int g;
void foo()
{
int i, local_g=g;
for (i=0; i100; i++){
fred(i,local_g);
}
}
6. 针对数据结构使用正确的数据类型
C编程人员对于数据类型一般都会有他们习惯上的假设,但是编译器却需要很谨慎地对待这些假设。比如,在几乎所有现代的计算机架构上,一个 unsigned char使用8位表示从0到255。一个C程序会假设对值为255的unsigned char加1会使其变为0。而实际上,现代32位处理器是不会执行上述的那种8位加法,而是进行32位数值的加法。因此,如果一个unsigned char的本地变量进行加法,编译器必须使用多条指令进行运算以保证加法后的符号扩展。因此,针对各种变量尤其是循环索引的变量,应该尽量多的在可以的地方使用int型变量。
另外,许多嵌入式处理器有16位乘法指令,而缺少32位乘法指令。在这种情况下,32位乘法将被仿效执行,一般情况下都是很慢的。如果数据被执行乘法操作并且计算结果不会超过16位的精度,那么就使用short或者unsigned short变量。
7. 不要用不直接的调用
这是通过包含传递参数的函数指针的调用,因为那会产生不可预知的边际效应(比如修改全局变量),使得优化难以进行。
8. 编写返回数值的函数而不是返回指针的函数
9. 传递变量时使用数值而不是指针或者全局变量
传递大结构的数据时,才使用指针。每个通过数值被传递的结构都应该在函数调用入口处被完全拷贝存储过。
10. 使用变量的地址会使程序性能降低
因为本地变量的地址会引起混淆,这如同全局变量一样。
11. 用const声明指针参数
如果函数体内不会修改到指针指向的对象,就要用const声明指针参数,这样可以让编译器避免不必要的反面假设。
12. 使用数组而不是指针,考虑下面通过指针访问数组的代码
for (i=0; i100; i++)
*p++ = ...
在每次循环中,*p被赋值。这种对指针对象的赋值会阻碍优化。某些情况下,指针指向它自己,那么这种赋值就会修改指针本身的值,这就会强迫编译器每次循环都重新加载该指针。还有,编译器不能确定这个指针不会被循环体以外的使用,所以每次循环外都要依据增量的数值更新该指针。因此,最好使用下面的代码:
for (i=0; i100; i++)
p[i] = ...
linux操作系统文章专题:linux操作系统详解(linux不再难懂)
评论