哪位高手给解释一下这个原因?
本帖最后由 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个字节,但是我的程序比例程还要短几十个语句,里外里可能差几十个字节
求模指令是大头
对非2次方的数字求模,一个C语言指令可以产生几十条汇编指令 ruanxianwu 发表于 2014-7-23 13:54
求模指令是大头
对非2次方的数字求模,一个C语言指令可以产生几十条汇编指令 ...
但俩程序都有求模运算啊 ruanxianwu 发表于 2014-7-23 13:54
求模指令是大头
对非2次方的数字求模,一个C语言指令可以产生几十条汇编指令 ...
并且俩程序是一样的求模运算 本帖最后由 tam2907 于 2014-7-23 14:32 编辑
”一个是我写的,一个是例程,运行结果类似“我看不然。
如果是你自建的工程,与别人建的工程比较,的确有可能。 >> 并且俩程序是一样的求模运算
不是一样。例程将要显示的f的个位提取出来查表后送显示(f%10),而你的是(i/1000),本身就是错的。 我还没看过这么长的程序 alias 发表于 2014-7-23 14:35
>> 并且俩程序是一样的求模运算
不是一样。例程将要显示的f的个位提取出来查表后送显示(f%10),而你的是(i ...
那个是错了,但是改过来一样的结果,还是我那个编译结果要大 tam2907 发表于 2014-7-23 14:29
”一个是我写的,一个是例程,运行结果类似“我看不然。
如果是你自建的工程,与别人建的工程比较,的确 ...
我都是测试过的,都是在四位数码管显示累加结果的,我那个当然会有暗影,不过我想问的不是这个问题,而是最终代码的问题。 同样优化后编译 看看结果如何 mcucow 发表于 2014-7-23 15:45
同样优化后编译 看看结果如何
当然是一样的环境了 zhiguangqi 发表于 2014-7-23 15:40
那个是错了,但是改过来一样的结果,还是我那个编译结果要大
改了还是错。
(i/10) 和 (i%10) 是不同的。 看一下汇编不就一目了然了么 alias 发表于 2014-7-23 16:07
改了还是错。
(i/10) 和 (i%10) 是不同的。
你有环境的话编译一下就知道了,没必要纠结这个,我这个也是测试的时候改错的,找不到问题根源 lcofjp 发表于 2014-7-23 16:27
看一下汇编不就一目了然了么
汇编当然不一样了,我看了,但是不知道什么原因导致的这个 zhiguangqi 发表于 2014-7-23 16:34
汇编当然不一样了,我看了,但是不知道什么原因导致的这个
你看了汇编的话,就能看到是哪些C语句导致指令指令增加的。
我觉得,差异可能出在这个上面
类似这样的语句PORTB = 0X02;
要比下面的代码多
RB0 = 0;
RB1 = 1;
你改下试试? zhiguangqi 发表于 2014-7-23 16:33
你有环境的话编译一下就知道了,没必要纠结这个,我这个也是测试的时候改错的,找不到问题根源 ...
没必要纠结?
把错的程式和正确的比较记忆使用量大小,你不觉得你是在浪费时间吗? >> 类似这样的语句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,至编译后会多占字节。
如果是差几百个字节,哪还有讨论的余地,几个字节,太浪费表情了。 alias 发表于 2014-7-23 19:57
>> 类似这样的语句PORTB = 0X02;
>> 要比下面的代码多
>>RB0 = 0;
这几个都是单字节指令好不
mon51 发表于 2014-7-23 20:21
如果是差几百个字节,哪还有讨论的余地,几个字节,太浪费表情了。
我想说的是,同一个函数在不同的位置为何编译出来结果差那么多
。而不是单纯讨论程序的长度 1、确保开花环境设置一样,可以这样测试,直接复制一份例程,在例程上面改成你的程序;
2、实在不行就比较一下汇编,代码不多,应该还是能看出来的。 zchong 发表于 2014-7-24 09:07
1、确保开花环境设置一样,可以这样测试,直接复制一份例程,在例程上面改成你的程序;
2、实在不行就比较 ...
其实关键就是这个语句PORTD=LED在我那里和例程里的汇编代码差别太大,为什么呢 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];
这三个部分中的取余、除法都是各自独立的
所以生成的代码就大了 yklstudent 发表于 2014-7-24 10:49
因为这是C编译器,感觉还是有点傻
代码改成如下,则可以更省:
#include
你说的最靠谱了,其实我就是想知道为什么会出这种情况。多谢 yklstudent 发表于 2014-7-24 10:49
因为这是C编译器,感觉还是有点傻
代码改成如下,则可以更省:
#include
的确又小了不少,这个C真是够傻的。是不是别的函数也会有这个现象发生呢?
页:
[1]