C51编写优化的代码

使用小模式的关键字是 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算法更有效。

粽子糖果 发表于09-19 10:05 浏览65535次
分享到:

已有0条评论

暂时还没有回复哟,快来抢沙发吧

添加一条新评论

只有登录用户才能评论,请先登录注册哦!

话题作者

粽子糖果
粽子糖果(总统)
金币:41631个|学分:51991个
立即注册
畅学电子网,带你进入电子开发学习世界
专业电子工程技术学习交流社区,加入畅学一起充电加油吧!

x

畅学电子网订阅号