打印

令人尴尬的 keil C编译器问题.

[复制链接]
7320|23
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
wxj1952|  楼主 | 2008-5-4 14:58 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
昔日,niuniu1983 “KEIL C 编译器的问题 ”的贴子提出的有关C51编译器的调试问题引人入胜,“C51真的那么逊吗?”实验一下。见下面模拟实验程序:

#include <reg51.h>
#define uchar unsigned char

uchar led_dly_table[10]={1,2,3,4,5,6,7,8,9};   

void led_dly_one_byte(uchar , bit ) ;

void main(void)
{
       while(1);
   
}
//--------------------------------------------------------------

void time0_over_int(void)interrupt 1 using 3    
{
uchar i ;                //            

TR0 = 0;
TL0 = i;
//TH0 = i>>8;    
TR0 = 1;

led_dly_one_byte(5,1);
}

//--------------------------------------------------------

void    led_dly_one_byte(uchar number, bit dp) 
{                       
  uchar    i;    

    i=led_dly_table[number];      
   
 if(dp) i&=0x7f;   
    
}
___________________________________________________________

keil下编译之:

C51 COMPILER V6.23a  REENT                                                                 05/03/2008 09:17:16 PAGE 4   

ASSEMBLY LISTING OF GENERATED OBJECT CODE


             ; FUNCTION main (BEGIN)
                                           ; SOURCE LINE # 11
                                           ; SOURCE LINE # 12
0000         ?C0001:
                                           ; SOURCE LINE # 14
                                           ; SOURCE LINE # 15
                                           ; SOURCE LINE # 17
0000 80FE              SJMP    ?C0001
             ; FUNCTION main (END)

             ; FUNCTION time0_over_int (BEGIN)
0000 C0E0              PUSH    ACC
0002 C0F0              PUSH    B
0004 C083              PUSH    DPH
0006 C082              PUSH    DPL
0008 C0D0              PUSH    PSW
000A 75D018            MOV     PSW,#018H
                                           ; SOURCE LINE # 20
                                           ; SOURCE LINE # 24
000D C28C              CLR     TR0
                                           ; SOURCE LINE # 25
000F 85008A      R     MOV     TL0,i
                                           ; SOURCE LINE # 27
0012 D28C              SETB    TR0
                                           ; SOURCE LINE # 29
0014 D200        R     SETB    ?_led_dly_one_byte?BIT
0016 7F05              MOV     R7,#05H
0018 120000      R     LCALL   _led_dly_one_byte
                                           ; SOURCE LINE # 30
001B D0D0              POP     PSW
001D D082              POP     DPL
001F D083              POP     DPH
0021 D0F0              POP     B
0023 D0E0              POP     ACC
0025 32                RETI    
             ; FUNCTION time0_over_int (END)


             ; FUNCTION _led_dly_one_byte (BEGIN)
                                           ; SOURCE LINE # 34
;---- Variable 'number' assigned to Register 'R7' ----
                                           ; SOURCE LINE # 35
                                           ; SOURCE LINE # 37
;---- Variable 'i' assigned to Register 'R7' ----
                                           ; SOURCE LINE # 38
                                           ; SOURCE LINE # 41
0000         ?C0006:
0000 22                RET     
             ; FUNCTION _led_dly_one_byte (END)

令人诧异的编译结果,函数_led_dly_one_byte 根本没有被编译!


问题在哪 ?


 顺便致谢niuniu1983 ,要不是他提出的精彩问题,也许我还会一直错过欣赏C51一道漂亮的风景。


 

相关帖子

沙发
wxj1952|  楼主 | 2008-5-4 15:05 | 只看该作者

第二种结果!

另:以上是采用C51 编译器 V6.23以上 版本得到的结果。
                                                                   
如果用C51编译器 V6.02版本 ,将能够得到niuniu1983 的结果 。  

C51 COMPILER V6.02  REENT                                                                                                                                
......

             ; FUNCTION _led_dly_one_byte (BEGIN)
;---- Variable 'number' assigned to Register 'R7' ----
                                           ; SOURCE LINE # 35
                                           ; SOURCE LINE # 36
                                           ; SOURCE LINE # 38
0000 7400        R     MOV     A,#LOW led_dly_table
0002 2F                ADD     A,R7
0003 F8                MOV     R0,A
0004 E6                MOV     A,@R0
0005 FF                MOV     R7,A
;---- Variable 'i' assigned to Register 'R7' ----
                                           ; SOURCE LINE # 39
0006 300003      R     JNB     dp,?C0006
0009 53077F            ANL     AR7,#07FH
                                           ; SOURCE LINE # 42
000C         ?C0006:
000C 22                RET     
             ; FUNCTION _led_dly_one_byte (END)

*********************************************************************

到底问题在那?是C51编译器的BUG?

使用特权

评论回复
板凳
niuniu1983| | 2008-5-4 15:07 | 只看该作者

都是临时变量的原因吧

使用特权

评论回复
地板
xuyaqi| | 2008-5-4 15:52 | 只看该作者

改分号编译没问题,看图。

使用特权

评论回复
5
brmcu| | 2008-5-4 16:02 | 只看该作者

同一个程序在不同的版本下有时候会有点问题

同一个程序在不同的版本下有时候会有点问题 我也碰到过 改下就可以

使用特权

评论回复
6
niuniu1983| | 2008-5-4 17:01 | 只看该作者

其实,这个问题在KEIL 的C51.pdf资料上写的很清楚了

刚刚看到。

不能怪编译器

使用特权

评论回复
7
ayb_ice| | 2008-5-4 19:07 | 只看该作者

不要轻易怀疑编译器有问题

虽然有时可能真的有点问题.

使用特权

评论回复
8
wxj1952|  楼主 | 2008-5-4 19:12 | 只看该作者

应该如何处理?“改一下就可以。” 改哪里?

总不能让我降低版本,回到V6.0以下编译器使用吧?人们现在用的都是8.0版本了。

4楼 xuyaqi 学长麻烦能否贴一下lst文件/SRC文件,FUNCTION _led_dly_one_byte (BEGIN)  函数有C51编译出的代码吗?

使用特权

评论回复
9
HWM| | 2008-5-4 19:35 | 只看该作者

是优化所致,将优化级别降低就可以。

但从语义上看没啥意义,被优化是自然的。

使用特权

评论回复
10
平常人| | 2008-5-4 21:27 | 只看该作者

好像不奇怪,因为执行函数led_dly_one_byte与否结果一样

估计是编译器发现这个函数(led_dly_one_byte)没有对任何全局变量造成影响,所以把它优化掉了。

使用特权

评论回复
11
xwj| | 2008-5-4 23:12 | 只看该作者

因为编译器的优化做得太聪明了

使用特权

评论回复
12
hotpower| | 2008-5-4 23:52 | 只看该作者

Keil C51肯定不如Keil ARM好用~~~

不过Keil的软件仿真还是不错的~~~

至少比IAR好用~~~

使用特权

评论回复
13
hkap| | 2008-5-5 09:46 | 只看该作者

这种问题习惯就好了

使用特权

评论回复
14
wlq_9| | 2008-5-5 10:03 | 只看该作者

主要是因为

大家都用它,心里面潜意识都把keil作为权威,平时偶尔发现点小问题都习惯了从自己身上找问题.其实keil做的真的很一般.

使用特权

评论回复
15
gyt| | 2008-5-5 10:49 | 只看该作者

11楼说得很对

使用特权

评论回复
16
wxj1952|  楼主 | 2008-5-5 11:44 | 只看该作者

谢HWM和各位学长。

HWM揭开了C51第一道风景,——优化级别。
    如果一个用户函数带有参数和内部临时局部变量时,C51编译器将为该函数的形参和局部变量(自动变量)预先分配保留(不单独)属于它自己使用的存储器空间,以便于在该函数被调用时,拷贝实参。像上面led_dly_one_byte 函数,编译器将为 number、dp、i  分配2个char 类型和一个bit类型内存空间。如果程序员忽略给出恰当的编译控制命令,那么C51编译器将按默认控制项进行编译。对于上例,编译器将按默认优化级别(9级)进行编译。它包含了所有优化级别控制功能。
    在第4级优化 OPTIMIZE(4)的重点中,有:

*寄存器变量:“使自动变量和函数参数尽可能位于工作寄存器中,只要有可能,将不为这些变量保留数据存储器空间。”

    这就是在上例中看到的结果,默认9级优化后,用工作寄存器R7代替了形参number,同时又代替了自动变量 i 。且函数操作代码被8级/9级 OPTIMIZE 优化掉了!
    降低优化级别,用#pragma  OT( 7),就可以使 led_dly_one_byte 函数被编译,并在V6.23版本下,看到V6.02版 的同样编译结果。
    设置 #pragma  OT(3),就可以让编译器为 number、 i  保留2个char 类存储器空间,并得到led_dly_one_byte 函数的全部——与using  3  无关的正确编译代码。
    所以,编译器没有问题,是我自己的问题!


   继续:“如果设置OT(4)以上,OT(7)以下优化级别”,所带来的问题。——它让我错过C51编译器的第二道风景。 

   继续:平常人说的也许C51优化有它的道理,那么我在函数中再加一条语句实验一下:估计编译结果会怎样?
   P1=i;


使用特权

评论回复
17
wxj1952|  楼主 | 2008-5-5 17:30 | 只看该作者

谢 平常人,很多问题旁观者清。

    经“平常人”提醒,修改了led_dly_one_byte 函数,加入P1=i ; 编译结果大不一样:即使默认9级优化,仍能得到函数编译代码。正如xwj 所说,C51编译器太聪明了,——德国人的严谨?它能够“看出”led_dly_one_byte 函数对于“面向动作”的过程化程序设计来说,没什么贡献;因而将其优化掉了!
    再次实验,将P1=i ; 语句删掉,将 void led_dly_one_byte( )函数定义为带有返回数值的类型,也就是说,对于主调函数来说,它必然是有所贡献的:

    uchar led_dly_one_byte(uchar,bit ) ;
   
   编译之,结果与希望的相同,没有被优化!

使用特权

评论回复
18
wxj1952|  楼主 | 2008-5-6 11:21 | 只看该作者

非常感谢所长提醒。我视其为第二道风景。

C51的第二道风景——volatile

   如果在一个常用变量的说明中加了volatile限定符,则通知编译器不对该变量进行寄存器变量优化。

   在上例 void  led_dly_one_byte( )函数定义中,将 uchar i ; 改为

       volatile uchar i ; 

则:即使不修改默认优化级别,void  led_dly_one_byte( )函数也能得到与using 3 无关的正确编译代码。因为变量 i 不再被R7替代,单独分配在了data存储器空间。

使用特权

评论回复
19
wswh2o| | 2008-5-6 11:28 | 只看该作者

为什么keil不做成标准的c编译器

没觉得这样省ram。

使用特权

评论回复
20
ayb_ice| | 2008-5-6 19:02 | 只看该作者

一点也不尴尬

这样的程序放到CW(FREESCALE)上估计也会被优化掉,因为我发现它也把一些没有用的程序被优化掉了。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

38

主题

757

帖子

1

粉丝