1、 使用盡量小的數據類型
能用unsiged就不用signed;能用char就不用int;能不用floating就不用;能用位操作不用算數。
2、使用自加、自減指令
通常使用自加、自減指令和復合賦值表達式(如a-=1 及a+=1 等)都能夠生成高質量的程序代碼,編譯器通常都能夠生成inc 和dec 之類的指令,而使用a=a+1 或a=a-1 之類的指令,有很多C 編譯器都會生成二到三個字節的指令。
3、減少運算的強度
可以使用運算量小但功能相同的表達式替換原來復雜的的表達式。
(1) 求余運算(條件是除數必須是2的n次冪才行)
N= N %8 可以改為N = N &7 9%8=1 1001 & (1000 - 1) =1001 & 0111 =1 // 1001是9的二進制表示,1000是8的二進制表示,8(2的3次冪)
說明:位操作只需一個指令周期即可完成,而大部分的C 編譯器的“%”運算均是調用子程序來完成,代碼長、執行速度慢。通常,只要求是求2n 方的余數,均可使用位操作的方法來代替。
(2) 平方運算
N=Pow(3,2) 可以改為N=3*3
說明:在有內置硬件乘法器的單片機中(如51 系列),乘法運算比求平方運算快得多, 因為浮點數的求平方是通過調用子程序來實現的,乘法運算的子程序比平方運算的子程序代碼短,執行速度快。
(3) 用位移代替乘法除法
N=M*8 可以改為N=M<<3,N=M/8 可以改為N=M>>3
說明:通常如果需要乘以或除以2n,都可以用移位的方法代替。如果乘以2n,都可以生成左移的代碼,而乘以其它的整數或除以任何數,均調用乘除法子程序。用移位的方法得到代碼比調用乘除法子程序生成的代碼效率高。實際上,只要是乘以或除以一個整數,均可以用移位的方法得到結果。
如N=M*9可以改為N=(M<<3)+M;
(4)函數和宏函數的區別
宏函數占用了大量的空間,而函數占用了時間。函數調用是要使用系統的棧來保存數據的,如果編譯器里有棧檢查選項,一般在函數的頭會嵌入一些匯編語句對當前棧進行檢查;同時,CPU也要在函數調用時保存和恢復當前的現場,進行壓棧和彈棧操作,所以,函數調用需要一些CPU時間。而宏函數不存在這個問題。宏函數僅僅作為預先寫好的代碼嵌入到當前程序,不會產生函數調用,所以僅僅是占用了空間,在頻繁調用同一個宏函數的時候,該現象尤其突出。
4、循環
(1)、循環語
對於一些不需要循環變量參加運算的任務可以把它們放到循環外面,這里的任務包括表達式、函數的調用、指針運算、數組訪問等,應該將沒有必要執行多次的操作全部集合在一起,放到一個init的初始化程序中進行。
(2)、延時函數:
通常使用的延時函數均采用自加的形式:
兩個函數的延時效果相似,但幾乎所有的C編譯對后一種函數生成的代碼均比前一種代碼少1~3個字節,因為幾乎所有的MCU均有為0轉移的指令,采用后一種方式能夠生成這類指令。在使用while循環時也一樣,使用自減指令控制循環會比使用自加指令控制循環生成的代碼更少1~3個字母。但是在循環中有通過循環變量"i"讀寫數組的指令時,使用預減循環時有可能使數組超界,要引起注意。
(3)while循環和do…while循環
用while循環時有以下兩種循環形式:
在這兩種循環中,使用do…while循環編譯后生成的代碼的長度短於while循環。
5、其它
比如使用在線匯編及將字符串和一些常量保存在程序存儲器中,均有利於優化。
6、i++ 和++i 的區別
void test1(void) { int i,x; i = 1; x = 1; x = i++; //先讓x變成i的值1,再讓i加1 printf("test1 x:%d\r\n", x); //x=1 printf("test1 i:%d\r\n", i); //i=2 } void test2(void) { int i,x; i = 1; x = 1; x = ++i; //先讓i加1, 再讓x變成i的值2 printf("test2 x:%d\r\n", x); //x=2 printf("test2 i:%d\r\n", i); //i=2 }
