打印
[AVR单片机]

GCC-AVR是开发工程师们开发AVR最好的选择!

[复制链接]
7766|51
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
宇宙飞船|  楼主 | 2007-7-17 14:37 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
今天看到一贴对GCC-AVR的评价,竟然写出放弃GCC-AVR的主贴!
俺不得不回应一下:
地球人都知道编译器对程序代码的优化不是永无止境的,代码的优化程度跟程序风格的写法有极大的关系。其实每一个合格的单片机C程序员必需了解手上C开发编译工具的性能,若连自已赖以为生的开发工具的都不能熟悉,就不配做一个程序开发人员。

俺先用硬件作过比较:
-----------------------------------------------------------
用过VHDL硬件描述语言的人都知道,逻辑寄存器的使用跟代码描述方式有关,实现相同的功能,一个有经验的硬件高手用结构描述,跟没有经验的菜鸟用行为描述,最后无论编译器优化性能如何的卓越,硬件高手用的逻辑就是比菜鸟用得少很多!
-----------------------------------------------------------
再用软件作个比较-----GCC-AVR编译:
对于单片机C编译器,若果实现相同的功能,同一优化级别下。
例如:对于同一条件逻辑判断,高手VS菜鸟,
高手会用:
  if(Uart_Byte_H==Cmd_Light_Dev)
     if(Uart_Byte_L!=0){
       Uart_Byte_L=12;
     }
------------------------
菜鸟会用:
  if((Uart_Byte_H==Cmd_Light_Dev) & (Uart_Byte_L!=0)){
      Uart_Byte_L=12;
     }

//---高手的代码编译后的长度--(仅是用了8条指令)--------
if(Uart_Byte_H==Cmd_Light_Dev)
    4616:    80 91 03 01     lds    r24, 0x0103
    461a:    83 30           cpi    r24, 0x03    ; 3
    461c:    39 f4           brne    .+14         ; 0x462c <main+0x17e>
   if(Uart_Byte_L!=0){
    461e:    80 91 04 01     lds    r24, 0x0104
    4622:    88 23           and    r24, r24
    4624:    19 f0           breq    .+6          ; 0x462c <main+0x17e>
      Uart_Byte_L=12;
    4626:    8c e0           ldi    r24, 0x0C    ; 12
    4628:    80 93 04 01     sts    0x0104, r24
     }  
*****************************************************
//----菜鸟的代码编译后的长度---(用了28条指令)------
if((Uart_Byte_H==Cmd_Light_Dev) & (Uart_Byte_L!=0)){
    45d8:    1c 82           std    Y+4, r1    ; 0x04
    45da:    1b 82           std    Y+3, r1    ; 0x03
    45dc:    80 91 03 01     lds    r24, 0x0103
    45e0:    83 30           cpi    r24, 0x03    ; 3
    45e2:    21 f4           brne    .+8          ; 0x45ec <main+0x13e>
    45e4:    81 e0           ldi    r24, 0x01    ; 1
    45e6:    90 e0           ldi    r25, 0x00    ; 0
    45e8:    9c 83           std    Y+4, r25    ; 0x04
    45ea:    8b 83           std    Y+3, r24    ; 0x03
    45ec:    1e 82           std    Y+6, r1    ; 0x06
    45ee:    1d 82           std    Y+5, r1    ; 0x05
    45f0:    80 91 04 01     lds    r24, 0x0104
    45f4:    88 23           and    r24, r24
    45f6:    21 f0           breq    .+8          ; 0x4600 <main+0x152>
    45f8:    21 e0           ldi    r18, 0x01    ; 1
    45fa:    30 e0           ldi    r19, 0x00    ; 0
    45fc:    3e 83           std    Y+6, r19    ; 0x06
    45fe:    2d 83           std    Y+5, r18    ; 0x05
    4600:    8b 81           ldd    r24, Y+3    ; 0x03
    4602:    9c 81           ldd    r25, Y+4    ; 0x04
    4604:    2d 81           ldd    r18, Y+5    ; 0x05
    4606:    3e 81           ldd    r19, Y+6    ; 0x06
    4608:    82 23           and    r24, r18
    460a:    93 23           and    r25, r19
    460c:    00 97           sbiw    r24, 0x00    ; 0
    460e:    19 f0           breq    .+6          ; 0x4616 <main+0x168>
      Uart_Byte_L=12;
    4610:    8c e0           ldi    r24, 0x0C    ; 12
    4612:    80 93 04 01     sts    0x0104, r24
     }

相关帖子

沙发
suwei123| | 2007-7-17 14:59 | 只看该作者

扯这个干吗呢,非得钻个牛角尖。

编译器的好处不是简单的优化代码这个事情的。
否则写汇编不就是最佳选择了。

使用特权

评论回复
板凳
宇宙飞船|  楼主 | 2007-7-17 15:10 | 只看该作者

同一功能的实现同一优化级别下:28:8 几乎是4:1 的代码长

2楼竟说是钻个牛角尖?!对于其它太多的技巧,请自已摸索去!对GCC-AVR只有半捅水,一知半解的人,请别在这里乱放**!

使用特权

评论回复
地板
大雁塔莱农| | 2007-7-17 15:19 | 只看该作者

如果编译器,这两种写法就应该一样

完全一样的逻辑,大多数人都会用第二种写法的
如果编译器这都不能合理优化,那只能说明设计者的弱智

很多人BS keil,但你去看看Keil的处理,就会明白的

---------------------------------
高手会用:
  if(Uart_Byte_H==Cmd_Light_Dev)
     if(Uart_Byte_L!=0){
       Uart_Byte_L=12;
     }
------------------------
菜鸟会用:
  if((Uart_Byte_H==Cmd_Light_Dev) & (Uart_Byte_L!=0)){
      Uart_Byte_L=12;
     }

使用特权

评论回复
5
大雁塔莱农| | 2007-7-17 15:24 | 只看该作者

倒塌,正确的写法应该是

  if((Uart_Byte_H==Cmd_Light_Dev) && (Uart_Byte_L!=0)){
      Uart_Byte_L=12;
     }

怪不得结果不对!

使用特权

评论回复
6
宇宙飞船|  楼主 | 2007-7-17 15:31 | 只看该作者

对于Keil的编译处理长度同样会不一样,做同一种判定

所用的指令:for 结构同Do 结构做出来的是两个长度,编译后相差很远,俺N年前测试过!DO结构编译出来的就象用汇编写的一样的短小,就象是汇编高手写出来的代码!

使用特权

评论回复
7
MicroMMU| | 2007-7-17 15:39 | 只看该作者

我倒,还振振有辞。

if((Uart_Byte_H==Cmd_Light_Dev) & (Uart_Byte_L!=0)){
      Uart_Byte_L=12;
     }

if(Uart_Byte_H==Cmd_Light_Dev)
     if(Uart_Byte_L!=0){
       Uart_Byte_L=12;
     }
相比明显多了运算。代码肯定长些.
只能说C语言没学好。

使用特权

评论回复
8
宇宙飞船|  楼主 | 2007-7-17 15:44 | 只看该作者

改正后,GCC-AVR编译出来跟高手用汇编写出来的是完全一样,

if((Uart_Byte_H==Cmd_Light_Dev) && (Uart_Byte_L!=0)){
    45d8:    80 91 03 01     lds    r24, 0x0103
    45dc:    83 30           cpi    r24, 0x03    ; 3
    45de:    39 f4           brne    .+14         ; 0x45ee <main+0x140>
    45e0:    80 91 04 01     lds    r24, 0x0104
    45e4:    88 23           and    r24, r24
    45e6:    19 f0           breq    .+6          ; 0x45ee <main+0x140>
      Uart_Byte_L=12;
    45e8:    8c e0           ldi    r24, 0x0C    ; 12
    45ea:    80 93 04 01     sts    0x0104, r24
     }
//----------------------------------------   
if(Uart_Byte_H==Cmd_Light_Dev)
    45ee:    80 91 03 01     lds    r24, 0x0103
    45f2:    83 30           cpi    r24, 0x03    ; 3
    45f4:    39 f4           brne    .+14         ; 0x4604 <main+0x156>
   if(Uart_Byte_L!=0){
    45f6:    80 91 04 01     lds    r24, 0x0104
    45fa:    88 23           and    r24, r24
    45fc:    19 f0           breq    .+6          ; 0x4604 <main+0x156>
      Uart_Byte_L=12;
    45fe:    8c e0           ldi    r24, 0x0C    ; 12
    4600:    80 93 04 01     sts    0x0104, r24
     }  

使用特权

评论回复
9
宇宙飞船|  楼主 | 2007-7-17 15:46 | 只看该作者

不好意思,很久没用这条语句,记错了!

使用特权

评论回复
10
arm爱好者| | 2007-7-17 16:01 | 只看该作者

re:

不可一世的高人也终于栽倒在自己的傲慢之下了!

使用特权

评论回复
11
mcubest| | 2007-7-17 18:09 | 只看该作者

呵呵,有意思

使用特权

评论回复
12
大雁塔菜农| | 2007-7-17 19:35 | 只看该作者

我倒~~~这马甲是个AVR高手~~~俺迷糊了~~~

使用特权

评论回复
13
大雁塔菜农| | 2007-7-17 19:45 | 只看该作者

哈哈~~~飞船估计是笔误了~~~

高手会用:
  if(Uart_Byte_H==Cmd_Light_Dev)
     if(Uart_Byte_L!=0){
       Uart_Byte_L=12;
     }
------------------------
菜鸟会用:
  if((Uart_Byte_H==Cmd_Light_Dev) & (Uart_Byte_L!=0)){
      Uart_Byte_L=12;
     }


俺不是高手,也非菜鸟,俺只会(Uart_Byte_L为无符号时):

if (Uart_Byte_L && (Uart_Byte_H == Cmd_Light_Dev))
{
  Uart_Byte_L=12;
}

俺认为次序和效率挂钩,不知这个代码长度是多少,上面的马甲给算算???

在这里先谢过了~~~

使用特权

评论回复
14
大雁塔菜农| | 2007-7-17 19:56 | 只看该作者

我以前确实做过GCCAVR优化的实验,一行有时代码长度是高点

不过GCCAVR要全是如此的倒塌时,那么俺放弃也没有什么错呀???

因为这样无形中把使用GCCAVR的人就分成了"高手和菜鸟"~~~

如果:

if (Uart_Byte_L && (Uart_Byte_H == Cmd_Light_Dev))
{
  Uart_Byte_L=12;
}

和:

if (Uart_Byte_L)
{
  if (Uart_Byte_H == Cmd_Light_Dev))
  {
    Uart_Byte_L=12;
  }
}

代码编译长度不一样的话,俺就后悔放弃的晚了~~~

使用特权

评论回复
15
大雁塔莱农| | 2007-7-17 20:13 | 只看该作者

错,这只和数据分布有关

很明显,LZ原意里Uart_Byte_H 和Uart_Byte_L应该是一起代表一个16位数,
即Uart_Byte = Uart_Byte_H * 256 + Uart_Byte_L

假如Uart_Byte分布在整个范围内(0~0xffff),那么(Uart_Byte_H==Cmd_Light_Dev)   和 (Uart_Byte_L!=0) 命中的概率都是1/256,未命中的概率为255/256,这时你的方法理论上可以节约下比较字节的那个周期,可以快一点点;因为未命中时才直接退出(少一次判断),而两个条件的未命中几率是一样的。

但是,如果数据Uart_Byte分布范围有限((Uart_Byte_H==Cmd_Light_Dev)   和 (Uart_Byte_L!=0) 命中的概率不等),那么,应该把未命中几率多的条件放前面,因为对于逻辑与 未命中时可以直接退出(少一次判断)

如果是多个条件逻辑或,那么就刚好相反,应该把 命中几率多的条件放前面,这样才可以增加直接退出的概率,以加快整体运行速度

使用特权

评论回复
16
大雁塔菜农| | 2007-7-17 20:17 | 只看该作者

我倒~~~上面的马甲还是个数学高手,估计语文水平比俺好

哈哈~~~这"来"和"采"概率统计是多少???

使用特权

评论回复
17
大雁塔莱农| | 2007-7-17 20:21 | 只看该作者

比如说:下面这种常见的情况15楼的代码会快很多

当Uart_Byte_H只有几个可能值,而Uart_Byte_L却会在0~0xff见分配时



PS:
除非循环出现的次数很多,否则这些**毛蒜皮的小时间都可以忽略不计,只优先考虑编程的工作效率和代码的可读性!

真要到这么斤斤计较的时候,那就的仔细对照汇编代码了

使用特权

评论回复
18
雁塔农艺师| | 2007-7-17 20:55 | 只看该作者

我都晕了~~~15楼不是"你"自己吗???哈哈~~~乱套了~~~

俺现在叫"农艺师"了~~~

使用特权

评论回复
19
雁塔农艺师| | 2007-7-17 20:59 | 只看该作者

俺一直喜欢IAR的__low_level_init()

而且它的位也特别简洁~~~

#define DDR_LEDR DDRB_Bit0
#define DDR_LEDG DDRB_Bit1
#define DDR_LED  DDRD_Bit7

#define DDR_Wdt   DDRB_Bit7
#define DDR_Power DDRD_Bit6
#define DDR_Beep  DDRD_Bit4

#define LEDR PORTB_Bit0
#define LEDG PORTB_Bit1
#define LED  PORTD_Bit7

#define Wdt    PORTB_Bit7
#define Power  PORTD_Bit6

#define Beep   PORTD_Bit4

使用特权

评论回复
20
brm00| | 2007-7-17 21:09 | 只看该作者

马甲确实比较多

看来以后只能凭ID认人了:)

使用特权

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

本版积分规则

75

主题

1664

帖子

4

粉丝