zhiguangqi 发表于 2014-7-23 13:33:05

哪位高手给解释一下这个原因?

本帖最后由 zhiguangqi 于 2014-7-23 16:32 编辑

有俩C 的程序,一个是我写的,一个是例程,运行结果类似,当然例程写的很好,片子是PIC16F877A ,软件是HITECH C 9.83,除了程序不同,其他的条件都一样,我把程序直接贴上方便大家看。我的问题就是,这俩程序很多语句是一样的,我写的语句少,编译结果却大,而那个例程语句多,可是编译结果却小,为什么呢?百思不得其解!(我只想知道产生这个结果的原因,而不是程序好不好)
:先把我的贴上
#include <pic.h>

__CONFIG(FOSC_HS & WDTE_OFF & LVP_OFF);


const unsigned char led[] =
{
        //定义表格一定要使用const,这样会做到程序存储区中
    0B00111111,            //"0"的字形表,0x3F
    0B00000110,            //"1"的字形表,0x06
    0B01011011,            //"2"的字形表,0x5B
    0B01001111,            //"3"的字形表,0x4F
    0B01100110,            //"4"的字形表,0x66
    0B01101101,            //"5"的字形表,0x6D
    0B01111101,            //"6"的字形表,0x7D
    0B00000111,            //"7"的字形表,0x07
    0B01111111,            //"8"的字形表,0x7F
    0B01101111,            //"9"的字形表,0x6F

};



void main (void)
{
       
        unsigned int i;
        unsigned char j;

       
       
       
        TRISD = 0X0;
        TRISB = 0X0;
        PORTB = 0X0;
        PORTD = 0X0;
       
        while(1)
        {       
               
               
                PORTD = 0;
                if (++i > 9999) i = 0;
               
               
               
                       
       
                PORTD = led;
                PORTB = 0X0;
               
               
                PORTD = led[(i % 1000) / 100];
                PORTB = 0X01;
               
       
                PORTD = led[(i % 100) / 10];
                PORTB = 0X02;
               
               
                PORTD = led;
                PORTB = 0X03;
               
                for (j = 0; j < 200; j++);
               
               
               
               
               
               
               
       
        }





}

我的程序的编译结果:

Memory Summary:
    Program space      used    F5h (   245) of2000h words   (3.0%)
    Data space         used    11h (    17) of   170h bytes   (4.6%)
    EEPROM space         used   0h (   0) of   100h bytes   (0.0%)
    Configuration bits   used   1h (   1) of   1h word    (100.0%)
    ID Location space    used   0h (   0) of   4h bytes   (0.0%)




这个是例程:

#include <pic.h>         //调用PIC16F87XA单片机的头文件

//根据选项,配置字应该如下所示:
//__CONFIG(HS&WRTEN&WDTDIS&BOREN&PWRTDIS&UNPROTECT&DUNPROT&DEBUGDIS&LVPDIS);

//实际使用中,这样太麻烦,对于默认选项,我们将其忽略掉:
__CONFIG(FOSC_HS & WDTE_OFF & LVP_OFF);

//---------------------------------------
//数码管字形表,供显示时查询
const unsigned char LED=
{                        //定义表格一定要使用const,这样会做到程序存储区中
    0B00111111,            //"0"的字形表,0x3F
    0B00000110,            //"1"的字形表,0x06
    0B01011011,            //"2"的字形表,0x5B
    0B01001111,            //"3"的字形表,0x4F
    0B01100110,            //"4"的字形表,0x66
    0B01101101,            //"5"的字形表,0x6D
    0B01111101,            //"6"的字形表,0x7D
    0B00000111,            //"7"的字形表,0x07
    0B01111111,            //"8"的字形表,0x7F
    0B01101111,            //"9"的字形表,0x6F
};

//---------------------------------------
//4位数码管相关I/O设置
#define U5ARB0         //4位数码管单元的U5(74HC138)的A脚接在RB0口上
#define U5BRB1         //4位数码管单元的U5(74HC138)的B脚接在RB1口上
#define U5CRB2         //4位数码管单元的U5(74HC138)的C脚接在RB2口上
//---------------------------------------

//---------------------------------------
//名称: 主函数
//公司:宁波芯动电子有限公司
//网址:www.MovingChip.com
//日期:20121009
//---------------------------------------
void main(void)            //主函数,单片机开机后就是从这个函数开始运行
{

    unsigned char c=0;   //定义一个char型变量,做延时用
    unsigned char d=0;   //定义一个char型变量,控制显示位置
    unsigned char e=0;   //定义一个char型变量,做延时用
    unsigned intf=0;   //定义一个int型变量,显示内容用,显示内容0-9999

    TRISB=0B11111000;      //初始化RB7-RB0的输入输出方向
    TRISD=0B00000000;      //初始化RD7-RD0的输入输出方向
    PORTB=0B00000000;      //初始化RB7-RB0的数值
    PORTD=0B00000000;      //初始化RD7-RD0的数值

    while(1)               //死循环,单片机初始化后,将一直运行这个死循环
    {

      for(c=0;c<200;c++);//做一个0-250的循环,不执行其他操作,只为延时
      if(++e>10)      //做一个延时,时间到将显示内容加1
      {
            e=0;         //清零,为下一次延时做准备
            if(++f>9999) f=0;//显示内容加1,因为只有4位显示,超过9999后归零
      }
      PORTD=0;         //关一次显示,以免显示出鬼影
      if(++d>3) d=0;   //先将d加1,然后判断是否大于3,大于3归零
      if(d==0)         //如果d=0,显示千位
      {
            U5A=0;         //U5A=0,U5B=0,U5C=0,选通数码管的千位进行显示
            U5B=0;         //U5A=0,U5B=0,U5C=0,选通数码管的千位进行显示
            U5C=0;         //U5A=0,U5B=0,U5C=0,选通数码管的千位进行显示
            PORTD=LED;       //将要显示的f的千位提取出来查表后送显示
      }
      else if(d==1)      //如果d=1,显示百位
      {
            U5A=1;         //U5A=1,U5B=0,U5C=0,选通数码管的百位进行显示
            U5B=0;         //U5A=1,U5B=0,U5C=0,选通数码管的百位进行显示
            U5C=0;         //U5A=1,U5B=0,U5C=0,选通数码管的百位进行显示
            PORTD=LED[(f%1000)/100]; //将要显示的f的百位提取出来查表后送显示
      }
      else if(d==2)      //如果d=2,显示十位
      {
            U5A=0;         //U5A=0,U5B=1,U5C=0,选通数码管的十位进行显示
            U5B=1;         //U5A=0,U5B=1,U5C=0,选通数码管的十位进行显示
            U5C=0;         //U5A=0,U5B=1,U5C=0,选通数码管的十位进行显示
            PORTD=LED[(f%100)/10];   //将要显示的f的十位提取出来查表后送显示
      }
      else if(d==3)      //如果d=3,显示个位
      {
            U5A=1;         //U5A=1,U5B=1,U5C=0,选通数码管的个位进行显示
            U5B=1;         //U5A=1,U5B=1,U5C=0,选通数码管的个位进行显示
            U5C=0;         //U5A=1,U5B=1,U5C=0,选通数码管的个位进行显示
            PORTD=LED;         //将要显示的f的个位提取出来查表后送显示
      }
    }
}


例程的编译结果:

Memory Summary:
    Program space      used    EBh (   235) of2000h words   (2.9%)
    Data space         used    13h (    19) of   170h bytes   (5.2%)
    EEPROM space         used   0h (   0) of   100h bytes   (0.0%)
    Configuration bits   used   1h (   1) of   1h word    (100.0%)
    ID Location space    used   0h (   0) of   4h bytes   (0.0%)



从编译结果来看是只差了10个字节,但是我的程序比例程还要短几十个语句,里外里可能差几十个字节

ruanxianwu 发表于 2014-7-23 13:54:48

求模指令是大头
对非2次方的数字求模,一个C语言指令可以产生几十条汇编指令

zhiguangqi 发表于 2014-7-23 13:57:11

ruanxianwu 发表于 2014-7-23 13:54
求模指令是大头
对非2次方的数字求模,一个C语言指令可以产生几十条汇编指令 ...

但俩程序都有求模运算啊

zhiguangqi 发表于 2014-7-23 13:58:03

ruanxianwu 发表于 2014-7-23 13:54
求模指令是大头
对非2次方的数字求模,一个C语言指令可以产生几十条汇编指令 ...

并且俩程序是一样的求模运算

tam2907 发表于 2014-7-23 14:29:03

本帖最后由 tam2907 于 2014-7-23 14:32 编辑

”一个是我写的,一个是例程,运行结果类似“我看不然。

如果是你自建的工程,与别人建的工程比较,的确有可能。

alias 发表于 2014-7-23 14:35:33

>> 并且俩程序是一样的求模运算

不是一样。例程将要显示的f的个位提取出来查表后送显示(f%10),而你的是(i/1000),本身就是错的。

rockyyangyang 发表于 2014-7-23 14:41:56

我还没看过这么长的程序                  

zhiguangqi 发表于 2014-7-23 15:40:13

alias 发表于 2014-7-23 14:35
>> 并且俩程序是一样的求模运算

不是一样。例程将要显示的f的个位提取出来查表后送显示(f%10),而你的是(i ...

那个是错了,但是改过来一样的结果,还是我那个编译结果要大

zhiguangqi 发表于 2014-7-23 15:42:03

tam2907 发表于 2014-7-23 14:29
”一个是我写的,一个是例程,运行结果类似“我看不然。

如果是你自建的工程,与别人建的工程比较,的确 ...

我都是测试过的,都是在四位数码管显示累加结果的,我那个当然会有暗影,不过我想问的不是这个问题,而是最终代码的问题。

mcucow 发表于 2014-7-23 15:45:56

同样优化后编译 看看结果如何

zhiguangqi 发表于 2014-7-23 15:54:38

mcucow 发表于 2014-7-23 15:45
同样优化后编译 看看结果如何

当然是一样的环境了

alias 发表于 2014-7-23 16:07:55

zhiguangqi 发表于 2014-7-23 15:40
那个是错了,但是改过来一样的结果,还是我那个编译结果要大

改了还是错。

(i/10) 和 (i%10) 是不同的。

lcofjp 发表于 2014-7-23 16:27:44

看一下汇编不就一目了然了么

zhiguangqi 发表于 2014-7-23 16:33:56

alias 发表于 2014-7-23 16:07
改了还是错。

(i/10) 和 (i%10) 是不同的。

你有环境的话编译一下就知道了,没必要纠结这个,我这个也是测试的时候改错的,找不到问题根源

zhiguangqi 发表于 2014-7-23 16:34:40

lcofjp 发表于 2014-7-23 16:27
看一下汇编不就一目了然了么

汇编当然不一样了,我看了,但是不知道什么原因导致的这个

lcofjp 发表于 2014-7-23 17:08:15

zhiguangqi 发表于 2014-7-23 16:34
汇编当然不一样了,我看了,但是不知道什么原因导致的这个

你看了汇编的话,就能看到是哪些C语句导致指令指令增加的。
我觉得,差异可能出在这个上面
类似这样的语句PORTB = 0X02;
要比下面的代码多
RB0 = 0;
RB1 = 1;
你改下试试?

alias 发表于 2014-7-23 19:35:36

zhiguangqi 发表于 2014-7-23 16:33
你有环境的话编译一下就知道了,没必要纠结这个,我这个也是测试的时候改错的,找不到问题根源 ...

没必要纠结?

把错的程式和正确的比较记忆使用量大小,你不觉得你是在浪费时间吗?

alias 发表于 2014-7-23 19:57:10

>> 类似这样的语句PORTB = 0X02;
>> 要比下面的代码多
>>RB0 = 0;
>>RB1 = 1;

完全不合逻辑。

PortB = 0x02 由 movlw 0x02 及 movwf portB 组成。 RB0=0, RB1=1 由 bcf portB,0 及 bsf portB,1 组成,大家都是占用2字节。

后者连续进行位元改写运作,在 PIC 的 R-M-W 限制下非常不可靠。好的编译器可能会在两个指令间插入 NOP,至编译后会多占字节。

mon51 发表于 2014-7-23 20:21:10

如果是差几百个字节,哪还有讨论的余地,几个字节,太浪费表情了。

zhiguangqi 发表于 2014-7-24 09:00:39

alias 发表于 2014-7-23 19:57
>> 类似这样的语句PORTB = 0X02;
>> 要比下面的代码多
>>RB0 = 0;


这几个都是单字节指令好不

zhiguangqi 发表于 2014-7-24 09:03:47

mon51 发表于 2014-7-23 20:21
如果是差几百个字节,哪还有讨论的余地,几个字节,太浪费表情了。

我想说的是,同一个函数在不同的位置为何编译出来结果差那么多
。而不是单纯讨论程序的长度

zchong 发表于 2014-7-24 09:07:00

1、确保开花环境设置一样,可以这样测试,直接复制一份例程,在例程上面改成你的程序;
2、实在不行就比较一下汇编,代码不多,应该还是能看出来的。

zhiguangqi 发表于 2014-7-24 09:54:58

zchong 发表于 2014-7-24 09:07
1、确保开花环境设置一样,可以这样测试,直接复制一份例程,在例程上面改成你的程序;
2、实在不行就比较 ...

其实关键就是这个语句PORTD=LED在我那里和例程里的汇编代码差别太大,为什么呢

yklstudent 发表于 2014-7-24 10:49:18

zhiguangqi 发表于 2014-7-24 09:54
其实关键就是这个语句PORTD=LED在我那里和例程里的汇编代码差别太大,为什么呢 ...

因为这是C编译器,感觉还是有点傻
代码改成如下,则可以更省:
#include <pic.h>

__CONFIG(FOSC_HS & WDTE_OFF & LVP_OFF);

const unsigned char led[] =
{
                                                        //定义表格一定要使用const,这样会做到程序存储区中
    0B00111111,                                //"0"的字形表,0x3F
    0B00000110,                                //"1"的字形表,0x06
    0B01011011,                                //"2"的字形表,0x5B
    0B01001111,                                //"3"的字形表,0x4F
    0B01100110,                                //"4"的字形表,0x66
    0B01101101,                                //"5"的字形表,0x6D
    0B01111101,                                //"6"的字形表,0x7D
    0B00000111,                                //"7"的字形表,0x07
    0B01111111,                                //"8"的字形表,0x7F
    0B01101111,                                //"9"的字形表,0x6F
};

void main (void)
{
        unsigned int i = 0;
        unsigned char j = 0;
        unsigned char k = 0;

        TRISD = 0X0;
        TRISB = 0X0;
        PORTB = 0X0;
        PORTD = 0X0;
      
        while(1)
        {
                for (j = 0; j < 200; j++);

                PORTD = 0;
                if (++i > 9999) i = 0;
               
                if(++k > 3) k = 0;
                if(k==0)
                {
                        PORTB = 0X0;
                        PORTD = led;
                }
                else if(k==1)
                {       
                        PORTB = 0X01;       
                        PORTD = led[(i % 1000) / 100];
                }
                else if(k==2)
                {
                        PORTB = 0X02;
                        PORTD = led[(i % 100) / 10];
                }
                else if(k==3)
                {
                        PORTB = 0X03;
                        PORTD = led;
                }
        }
}

分析原因,编译器对
if()
{
}
else if()
{
}
else if()
{
}
else if()
{
}
结构内的代码做了不一样的处理,具体就是
1、PORTD = led[(i % 100) / 10];
汇编肯定包含了汇编取余、除法部分
2、PORTD = led;
除法部分调用了1中的处分部分
3、PORTD = led[(i % 1000) / 100];
则是直接调用了1的取余、除法部分;
这样一来,就省了不少FLASH了嘛

不采用
if()
{
}
else if()
{
}
else if()
{
}
else if()
{
}
结构你写的代码,分析编译后的汇编
PORTD = led;
PORTD = led[(i % 1000) / 100];
PORTD = led[(i % 100) / 10];
这三个部分中的取余、除法都是各自独立的
所以生成的代码就大了

zhiguangqi 发表于 2014-7-24 13:52:03

yklstudent 发表于 2014-7-24 10:49
因为这是C编译器,感觉还是有点傻
代码改成如下,则可以更省:
#include


你说的最靠谱了,其实我就是想知道为什么会出这种情况。多谢

zhiguangqi 发表于 2014-7-24 13:59:06

yklstudent 发表于 2014-7-24 10:49
因为这是C编译器,感觉还是有点傻
代码改成如下,则可以更省:
#include


的确又小了不少,这个C真是够傻的。是不是别的函数也会有这个现象发生呢?
页: [1]
查看完整版本: 哪位高手给解释一下这个原因?