學過單片機的人大都知道“流水燈”或“跑馬燈”之類的名稱,具體實現的效果就是按固定規律地迴圈地顯示某組變化。如用一個位元組長度的空間來實現“跑馬燈”,可以是使該位元組的值的變化過程為:
“0000 0001B” -> "0000 0010B” -> "0000 0100B” -> "0000 1000B” -> "0001 0000B” -> "0010 0000B” -> "0100 0000B” -> "1000 0000B” -> "0000 0001B” (迴圈)
假設,現在需要實現將一個int類型變數中的值從0至9的“跑馬燈”變化過程,那麼一般的方法是:
初版:
int val = 0;while(1){val++;if( val > 9 )val = 0;}//End;
在Keil uv3環境中使用ATMEL 89C51配置,編譯後的彙編代碼為:
C:0x0000 020010 LJMP C:0010 2: void main() 3: { 4: unsigned char val = 0; 5: C:0x0003 E4 CLR AC:0x0004 FF MOV R7,A 6: while(1) 7: { 8: val++; C:0x0005 0F INC R7 9: if( val > 9 ) C:0x0006 EF MOV A,R7C:0x0007 D3 SETB CC:0x0008 9409 SUBB A,#0x09C:0x000A 40F9 JC C:0005 10: val = 0; C:0x000C E4 CLR AC:0x000D FF MOV R7,A 11: } C:0x000E 80F5 SJMP C:0005C:0x0010 787F MOV R0,#0x7FC:0x0012 E4 CLR AC:0x0013 F6 MOV @R0,AC:0x0014 D8FD DJNZ R0,C:0013C:0x0016 758107 MOV SP(0x81),#0x07C:0x0019 020003 LJMP main(C:0003)
精簡修改版:
int val = 0;while(1){if( (++val) > 9 )val = 0;}
在Keil uv3環境中使用ATMEL 89C51配置,編譯後的彙編代碼為:
C:0x0000 020010 LJMP C:0010 2: void main() 3: { 4: unsigned char val = 0; 5: C:0x0003 E4 CLR AC:0x0004 FF MOV R7,A 6: while(1) 7: { 8: if( (++val) > 9 ) C:0x0005 0F INC R7C:0x0006 EF MOV A,R7C:0x0007 D3 SETB CC:0x0008 9409 SUBB A,#0x09C:0x000A 40F9 JC C:0005 9: val = 0; C:0x000C E4 CLR AC:0x000D FF MOV R7,A 10: } C:0x000E 80F5 SJMP C:0005C:0x0010 787F MOV R0,#0x7FC:0x0012 E4 CLR AC:0x0013 F6 MOV @R0,AC:0x0014 D8FD DJNZ R0,C:0013C:0x0016 758107 MOV SP(0x81),#0x07C:0x0019 020003 LJMP main(C:0003)
從上面兩個例子來看,KeilC51對源檔案進行編譯後,產生的彙編代碼一模一樣,也就是說,前面兩個編程方法,雖然從C語言的角度看有些許差異,但最終編譯為機器碼後,前後兩個代碼的執行效率是一樣的。
以上兩種C語言格式的編程方法,是目前為止筆者所掌握的方法,但是今日學習張孝祥所著的《JAVA就業培訓教程》時,瞭解至一種新的編程方法或者說是編程思路,用來實現此例中的”跑馬燈“效果過程如下:
unsigned char val = 0;while(1){val = (val+1)%10;}
在Keil uv3環境中使用ATMEL 89C51配置,編譯後的彙編代碼為:
C:0x0000 020010 LJMP C:0010 2: void main() 3: { 4: unsigned char val = 0; 5: C:0x0003 E4 CLR AC:0x0004 FF MOV R7,A 6: while(1) 7: { 8: val = (val+1)%10; C:0x0005 0F INC R7C:0x0006 EF MOV A,R7C:0x0007 D3 SETB CC:0x0008 9409 SUBB A,#0x09C:0x000A 40F9 JC C:0005 9: } C:0x000C E4 CLR AC:0x000D FF MOV R7,A 10: }C:0x000E 80F5 SJMP C:0005C:0x0010 787F MOV R0,#0x7FC:0x0012 E4 CLR AC:0x0013 F6 MOV @R0,AC:0x0014 D8FD DJNZ R0,C:0013C:0x0016 758107 MOV SP(0x81),#0x07C:0x0019 020003 LJMP main(C:0003)
結果是筆者發現,對上面三種C語言風格的不同的編程方法(或稱過程),經過KeilC51編譯器編譯為彙編代碼後,彙編代碼竟然一模一樣。既然彙編代碼一樣,那麼相應的機器代碼也就一樣,最終表現出來的代碼執行效率、時間就是一樣的。
至此,筆者驚訝於Keil公司的編譯器竟是如此"高效“和”智能化“,為同一目標而編寫的,但使用不同風格的編程方法編寫出來的程式,代碼經過編譯後,最終的執行效率竟然幾乎一致。
由此得出,Keil對C語言的原始碼有非常高效的編譯方法,使同一目的但不同編程方法實現的代碼,最終在硬體上實現非常高效的執行效率。
那麼,既然編譯器如此高效,是否意味著:使用者可以隨意編程,而不考慮編譯效率的問題呢?這個問題,有待繼續學習、研究!