学过单片机的人大都知道“流水灯”或“跑马灯”之类的名称,具体实现的效果就是按固定规律地循环地显示某组变化。如用一个字节长度的空间来实现“跑马灯”,可以是使该字节的值的变化过程为:
“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 A C: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,R7 C:0x0007 D3 SETB C C:0x0008 9409 SUBB A,#0x09 C:0x000A 40F9 JC C:0005 10: val = 0; C:0x000C E4 CLR A C:0x000D FF MOV R7,A 11: } C:0x000E 80F5 SJMP C:0005 C:0x0010 787F MOV R0,#0x7F C:0x0012 E4 CLR A C:0x0013 F6 MOV @R0,A C:0x0014 D8FD DJNZ R0,C:0013 C:0x0016 758107 MOV SP(0x81),#0x07 C: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 A C:0x0004 FF MOV R7,A 6: while(1) 7: { 8: if( (++val) > 9 ) C:0x0005 0F INC R7 C:0x0006 EF MOV A,R7 C:0x0007 D3 SETB C C:0x0008 9409 SUBB A,#0x09 C:0x000A 40F9 JC C:0005 9: val = 0; C:0x000C E4 CLR A C:0x000D FF MOV R7,A 10: } C:0x000E 80F5 SJMP C:0005 C:0x0010 787F MOV R0,#0x7F C:0x0012 E4 CLR A C:0x0013 F6 MOV @R0,A C:0x0014 D8FD DJNZ R0,C:0013 C:0x0016 758107 MOV SP(0x81),#0x07 C: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 A C:0x0004 FF MOV R7,A 6: while(1) 7: { 8: val = (val+1)%10; C:0x0005 0F INC R7 C:0x0006 EF MOV A,R7 C:0x0007 D3 SETB C C:0x0008 9409 SUBB A,#0x09 C:0x000A 40F9 JC C:0005 9: } C:0x000C E4 CLR A C:0x000D FF MOV R7,A 10: } C:0x000E 80F5 SJMP C:0005 C:0x0010 787F MOV R0,#0x7F C:0x0012 E4 CLR A C:0x0013 F6 MOV @R0,A C:0x0014 D8FD DJNZ R0,C:0013 C:0x0016 758107 MOV SP(0x81),#0x07 C:0x0019 020003 LJMP main(C:0003)
结果是笔者发现,对上面三种C语言风格的不同的编程方法(或称过程),经过KeilC51编译器编译为汇编代码后,汇编代码竟然一模一样。既然汇编代码一样,那么相应的机器代码也就一样,最终表现出来的代码执行效率、时间就是一样的。
至此,笔者惊讶于Keil公司的编译器竟是如此"高效“和”智能化“,为同一目标而编写的,但使用不同风格的编程方法编写出来的程序,代码经过编译后,最终的执行效率竟然几乎一致。
由此得出,Keil对C语言的源代码有非常高效的编译方法,使同一目的但不同编程方法实现的代码,最终在硬件上实现非常高效的执行效率。
那么,既然编译器如此高效,是否意味着:用户可以随意编程,而不考虑编译效率的问题呢?这个问题,有待继续学习、研究!