針對嵌入式SoC應(yīng)用的C編程優(yōu)化
5. 使用本地變量替代全局變量
這是因為全局變量會在整個程序的生命周期里面保留數(shù)值。編譯器必須認為全局變量可能通過指針被訪問。考慮下面的代碼:
int g;
void foo()
{
int i;
for (i=0; i100; i++){
fred(i,g);
}
}
理想情況下,g在每次fred循環(huán)時被加載一次,并且它的值將被傳遞到一個寄存器里面給fred函數(shù)使用。但是,編譯器不知道fred是否會修改g 的值。如果fred不會修改g的值,你應(yīng)該像下面一樣,使用本地變量。這樣做可以避免每次調(diào)用fred函數(shù)時加載g到一個寄存器里面。
int g;
void foo()
{
int i, local_g=g;
for (i=0; i100; i++){
fred(i,local_g);
}
}
6. 針對數(shù)據(jù)結(jié)構(gòu)使用正確的數(shù)據(jù)類型
C編程人員對于數(shù)據(jù)類型一般都會有他們習(xí)慣上的假設(shè),但是編譯器卻需要很謹慎地對待這些假設(shè)。比如,在幾乎所有現(xiàn)代的計算機架構(gòu)上,一個 unsigned char使用8位表示從0到255。一個C程序會假設(shè)對值為255的unsigned char加1會使其變?yōu)?。而實際上,現(xiàn)代32位處理器是不會執(zhí)行上述的那種8位加法,而是進行32位數(shù)值的加法。因此,如果一個unsigned char的本地變量進行加法,編譯器必須使用多條指令進行運算以保證加法后的符號擴展。因此,針對各種變量尤其是循環(huán)索引的變量,應(yīng)該盡量多的在可以的地方使用int型變量。
另外,許多嵌入式處理器有16位乘法指令,而缺少32位乘法指令。在這種情況下,32位乘法將被仿效執(zhí)行,一般情況下都是很慢的。如果數(shù)據(jù)被執(zhí)行乘法操作并且計算結(jié)果不會超過16位的精度,那么就使用short或者unsigned short變量。
7. 不要用不直接的調(diào)用
這是通過包含傳遞參數(shù)的函數(shù)指針的調(diào)用,因為那會產(chǎn)生不可預(yù)知的邊際效應(yīng)(比如修改全局變量),使得優(yōu)化難以進行。
8. 編寫返回數(shù)值的函數(shù)而不是返回指針的函數(shù)
9. 傳遞變量時使用數(shù)值而不是指針或者全局變量
傳遞大結(jié)構(gòu)的數(shù)據(jù)時,才使用指針。每個通過數(shù)值被傳遞的結(jié)構(gòu)都應(yīng)該在函數(shù)調(diào)用入口處被完全拷貝存儲過。
10. 使用變量的地址會使程序性能降低
因為本地變量的地址會引起混淆,這如同全局變量一樣。
11. 用const聲明指針參數(shù)
如果函數(shù)體內(nèi)不會修改到指針指向的對象,就要用const聲明指針參數(shù),這樣可以讓編譯器避免不必要的反面假設(shè)。
12. 使用數(shù)組而不是指針,考慮下面通過指針訪問數(shù)組的代碼
for (i=0; i100; i++)
*p++ = ...
在每次循環(huán)中,*p被賦值。這種對指針對象的賦值會阻礙優(yōu)化。某些情況下,指針指向它自己,那么這種賦值就會修改指針本身的值,這就會強迫編譯器每次循環(huán)都重新加載該指針。還有,編譯器不能確定這個指針不會被循環(huán)體以外的使用,所以每次循環(huán)外都要依據(jù)增量的數(shù)值更新該指針。因此,最好使用下面的代碼:
for (i=0; i100; i++)
p[i] = ...
linux操作系統(tǒng)文章專題:linux操作系統(tǒng)詳解(linux不再難懂)
評論