查看: 3680|回复: 2

Keil C51的一些有趣特性

[复制链接]
  • TA的每日心情
    无聊
    2016-12-20 15:08
  • 签到天数: 510 天

    连续签到: 1 天

    [LV.9]以坛为家II

    发表于 2013-4-6 15:25:23 | 显示全部楼层 |阅读模式
    分享到:
      关于C51函数在调用前和调用后定义产生的代码不一样这个问题,我刚才也碰到了。自己试了下,发现在调用前定义确实会是代码更少,执行时间更少。至于是什么原因,我也不知道。百度了一下,发下下面这篇文章的主人也发现了这个问题,不过他也没能给出确切的解释。有人说可以勾选Global  Register Coloring来解决,不过我试了下,好像没区别。不知道有人可以解释这个问题吗?
      
            Keil C51的一些有趣特性

    作者:yanfeng
    E-mail:szq106@163.com

      Keil c51号称作为51系列单片机最好的开发环境,大家一定都很熟悉。它的一些普通的特性大家也都了解,(书上也都说有)如:因为51内的RAM很小,C51的函数并不通过堆栈传递参数(重入函数除外),局部变量也不存储在堆栈中,而是存在于固定的RAM中及寄存器中。那么看一下下面的程序。

    void fun1(unsigned char i)
    {
           …
    }

      正常情况参数i通过R7传入函数,那么它的实际地址在什么地方呢?就是R7吗?回答这个问题之前我们先来了解keil c51的几个有趣的特性(不考虑重入函数)。

    一、              函数在调用前定义与在调用后定义产生的代码是有很大差别的(特别是在优化级别大于3级时)。(本人也不太清楚为什么,大概因为在调用前定义则调用函数已经知道被调用函数对寄存器的使用情况,则可对函数本身进行优化;而在调用后进行定义则函数不知被调用函数对寄存器的使用情况,它默认被调用函数对寄存器(ACC、 B、 DPH、 DPL、 PSW、 R0、 R1、 R2、 R3、R 4、 R5、, R6、 R7)都已经改变,因此不在这些寄存器中存入有效的数据)

    二、              函数调用函数时除在堆栈中存入返回地址之外,不在堆栈中保存其它任何寄存器(ACC、 B、 DPH、 DPL、 PSW、 R0、 R1、 R2、 R3、R 4、 R5、, R6、 R7)的内容。(除非被调用函数使用了using特性)

    三、              中断函数是一个例外,它会计算自身及它所调用的函数对寄存器(ACC、 B、 DPH、 DPL、 PSW、 R0、 R1、 R2、 R3、R 4、 R5、, R6、 R7)的改变,并保存相应它认为被改变了的寄存器。

    四、              使用C写程序时,尽量少使用using n (n=0,1,2,3)特性。(这个特性在本人使用的过程中存在一些问题,不知算不算是一个小bug)
    以下的试验都是在(环境 keil c51 v7.20)中,优化级为default下完成。

      先看第一个特性问题。
    例1:
    void fun2(void)
    {

    }

    void fun1(unsigned char i)
    {
           fun2();
           while(i--);
    }

      它的汇编代码如下:
    ; void fun2(void)
           RSEG  ?PR?fun2?
    fun2:
    ; {
                         ; SOURCE
    ; }
           RET      
    ; END OF fun2

    ; void fun1(unsigned char i)
           RSEG  ?PR?_fun1?
    _fun1:
           USING    0
    ;---- Variable 'i?240' assigned to Register 'R7' ----
    ; {
    ;     fun2();
           LCALL       fun2
    ;     while(i--);
           MOV         R6,AR7
           DEC         R7
           MOV         A,R6
           JNZ         ?C0003
    ; }
           RET      
    ; END OF _fun1

      从中可以看到fun2()在fun1()前先定义,fun1()知道fun2()对寄存器的使用情况,知道R7没有改变,而参数i存于R7中,即i既是R7。(;---- Variable 'i?140' assigned to Register 'R7' ----)
      看另一情况
    void fun2(void);

    void fun1(unsigned char i)
    {
           fun2();
           while(i--);
    }

    void fun2(void)
    {

    }
      汇编代码如下:

    ; void fun1(unsigned char i)
           RSEG  ?PR?_fun1?
    _fun1:
           USING    0
           MOV         i?140,R7
    ; {
    ;     fun2();
           LCALL       fun2
    ?C0002:
    ;     while(i--);
           MOV         R7,i?140
           DEC         i?140
           MOV         A,R7
           JNZ         ?C0002
    ; }
    ?C0004:
           RET      
    ; END OF _fun1

    ; void fun2(void)
           RSEG  ?PR?fun2?
    fun2:
    ; {
                         ; SOURCE
    ; }


    回复

    使用道具 举报

  • TA的每日心情

    2013-8-4 18:50
  • 签到天数: 6 天

    连续签到: 1 天

    [LV.2]偶尔看看I

    发表于 2013-4-6 17:36:57 | 显示全部楼层
    mark。改天看
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2023-9-15 06:28
  • 签到天数: 3747 天

    连续签到: 60 天

    [LV.Master]伴坛终老

    发表于 2013-4-7 08:23:47 | 显示全部楼层
    值得一看!!!
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条



    手机版|小黑屋|与非网

    GMT+8, 2024-11-15 09:09 , Processed in 0.130295 second(s), 18 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.