学过单片机的人大都知道“流水灯”或“跑马灯”之类的名称,具体实现的效果就是按固定规律地循环地显示某组变化。如用一个字节长度的空间来实现“跑马灯”,可以是使该字节的值的变化过程为:
“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语言的源代码有非常高效的编译方法,使同一目的但不同编程方法实现的代码,最终在硬件上实现非常高效的执行效率。
那么,既然编译器如此高效,是否意味着:用户可以随意编程,而不考虑编译效率的问题呢?这个问题,有待继续学习、研究!