C51编写优化的代码 作者[stevewh]©
--- 摘自《C51BBS离线版光盘》---

Keil Software — C51 Compiler User’s Guide 341
C附录C. 编写优化的代码
    本文列举了一些针对8051单片机及其C51编译器的可以提高软件效能的方法(如:生成更小的
代码,获得更快的运行速度等)。在大多数情况下,这些方法都可以起到很好的作用。存储器模式
/Memory Model 减少代码尺寸和提高运行速度的最有效的方式是将编译器的存储器模式设定为小模
式。该模式下,编译器可以生成最小的代码。
    使用小模式的关键字是 SMALL。 在小模式下,所有的变量(除非是显式地进行了存储位置申
明),都存放在8051芯片的内部存储器中。而8051对内部存储器的访问速度是最快的(典型情况下
为1或2个时钟周期),并且产生的访问这些变量的代码也是最少的,指令是最短的。请参看下面的
循环代码:
    for (i = 0; i < 100; i++)
    {
        do_nothing ();
    }
    在不同的编译模式下(小模式和巨模式),将生成不同的目标代码。
stmt level source
1 #pragma small
2
3 void do_nothing (void);
4
5
6 void func (void)
7 {
8 1 unsigned char i;
9 1
10 1 for (i = 0; i < 100; i++)
11 1 {
12 2     do_nothing ();
13 2 }
14 1 }
; FUNCTION func (BEGIN)
; SOURCE LINE #10
0000 E4             CLR A
0001 F500 R         MOV i,A
0003            ?C0001:
0003 E500 R         MOV A,i
0005 C3             CLR C
0006 9464           SUBB A,#064H
0008 5007           JNC ?C0004
; SOURCE LINE #12
000A 120000 E       LCALL do_nothing
; SOURCE LINE #13
000D 0500 R         INC i
000F 80F2           SJMP ?C0001
; SOURCE LINE #14
0011            ?C0004:
0011 22             RET
; FUNCTION func (END)
    在小模式下,变量I被放置在内部数据存储器中。访问变量I的指令,如:

        MOV     A,i
 和     INC     I
    只需要2字节。每条指令运行只需要1个时钟周期。整个代码长度只有17字节。
下面是同样的代码在巨模式下的编译结果:
; FUNCTION func (BEGIN)
; SOURCE LINE #10
0000 E4             CLR A
0001 900000 R       MOV DPTR,#i
0004 F0             MOVX @DPTR,A
0005            ?C0001:
0005 900000 R       MOV DPTR,#i
0008 E0             MOVX A,@DPTR
0009 C3             CLR C
000A 9464           SUBB A,#064H
000C 500B           JNC ?C0004
; SOURCE LINE #12
000E 120000 E       LCALL do_nothing
; SOURCE LINE #13
0011 900000 R       MOV DPTR,#i
0014 E0             MOVX A,@DPTR
0015 04             INC A
0016 F0             MOVX @DPTR,A
0017 80EC           SJMP ?C0001
; SOURCE LINE #14
0019            ?C0004:
0019 22             RET
; FUNCTION func (END)
    在巨模式下,变量i被放置在外部数据存储器中。为访问变量I,编译器必须首先加载数据指针
指向正确的地址(参见偏移0001h到0004h)。这2条指令就需要4个时钟周期。使变量i 增量的操
作需要6 字节的存储空间及7个时钟周期。总的代码大小达到25 字节。变量定位原则是将需要频繁
访问的数据对象放置在8051的内部数据存储器中。硬件访问内部数据存储器要比访问外部数据存储
器有效的多。内部数据存储器由寄存器组、位变量区域、堆栈和其它用户自定义变量共享。可以使
用关键字data来指定。
    由于受存储容量的限制(内部数据存储器为128字节,最多256字节)。 在整个软件中使用的
所有该类型变量都将占据这个区域,并且总的尺寸不能超过相应芯片的物理限制。在某些情况下,
就不得不将一些数据对象放置到外部数据存储器中。有2种办法可以进行该操作。

一是:改变存储模式,让编译器来自动完成该操作。这是最简单的方法,但需要产生更多的代码并
     降低运行速度。
二是:手工将需要放置在外部数据存储器中的数据对象使用关键字xdata进行申明。这种方式不会
     产生额外的代码。

变量尺寸
    8051系列是8位的CPU。使用8位的数据类型将比使用其它类型的数据要有效的多(如:char
和unsigned char就比使用int或long类型有效)。所以,在任何情况下应该首先使用最短的数
据类型。
    C51编译器直接支持所有的字节操作指令。除非特别指明,否则字节类型不会被转换成整数类
型来操作。参见INTPROMOTE关键字。
例如:两个字节类型的数据乘操作,将直接使用8051的单指令MUL AB。而如果使用其它类型的数
据,则会导致对编译器库函数的调用。

无符号类型Unsigned
    8051系列的处理器并不直接支持浮点数的运算。因此,编译器必须对浮点数运算产生额外的
代码。因此,任何时候都必须首先考虑使用无符号数据类型。

局部变量
    在遇到循环或其它临时计算操作时,应尽可能地使用局部变量。作为编译器优化处理过程的一
部分,临时变量将被编译器尽可能地放置在寄存器中。而寄存器访问是最快速的。在具体程序中,
可以申明为unsigned char和unsigned int变量类型。

其它原因
    通常最影响程序代码质量的原因并不是编译器生成代码的效率,而是软件本身为解决其目标问
题而使用的算法类型。采用更有效的算法,通常比其它方式来达到减少代码尺寸和提高运行速度的
目的更为有效。例如:heap排序算法总是比bubble算法更有效。
Copyright© 2001-2002, 晓奇工作室 E-Mail:info*xiao-qi.com