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