前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【编译器玄学研究报告】第二期——break

【编译器玄学研究报告】第二期——break

作者头像
Mculover666
发布2020-07-16 14:55:31
3490
发布2020-07-16 14:55:31
举报
文章被收录于专栏:TencentOS-tinyTencentOS-tiny

【说在前面的话】

编译器玄学报告第一期出来后,并没有任何人理睬我在文章一开头留下的问题,相反大部分人都是来围观“闰年更新”的

……更有甚者感慨:我娃都出生了,这个公众号终于更新了。真的非常非常抱歉,感觉辜负了很多人的期待;同时也非常非常的感谢,感谢你们的耐心和信任——为了纪念这一时刻,我准备就大家非常信赖和依恋的armcc(Arm Compiler 5)爆个黑料。让我们来围观一个如假包换的编译器bug。


【正文】

Arm Compiler 5,也就是大家熟悉的armcc,距离官方2017年最后一次更新已经过去3年多了。实际上官方早在2016年发布Arm Compiler 5.06u3的时候就已经通过各种渠道对外界喊话——“我要是再更新armcc,我就卖了我自己”,结果2017年,5.06u6不期而至,孙正义爸爸的钱还是“真香”的——这里也许有些许戏虐的成分在里面,但armcc接近软件生命周期的终点是不争的事实:

  • armcc 真的太老了!也许用户用起来感觉还挺趁手,但实际上已经是“屎山”一座了;

今天,我们就给大家展示一个Arm Compiler 5.06u6 “最终绝对不改版6” 中一个惊为天人的BUG。

1、准备好一个新鲜的 Arm Compiler 5.06u6。如果不确定自己的armcc是不是这一版本,可以打开MDK的help->About,如果你是日常的armcc玩家,应该可以看到类似如下的信息(是的,就是这个 V5.06 update 6

2、随便建立一个可以编译和调试的例子工程,并将优化等级设置为 -Otime -O3。具体方法如图所示:

3、插入以下的测试代码

代码语言:javascript
复制
#include <stdio.h>

void break_tesk(uint_fast8_t chValue)
{
    printf("entering switch...\r\n");
    switch (chValue >> 4) {
        case 0: 
            printf("do something...");
            break;
        case 1: 
            printf("do something...");
            break;
        case 2:
            do {
                printf("\tInput is 0x%02x", chValue);
                if ((chValue & 0x0F) < 7) {
                    break;
                }
                printf("You will not see this");
            } while(0);
            printf("\tYou should see this ");
            break;
        default:
            printf("it is a default");
            break;
    }
    printf("\r\nleave switch...\r\n ");
}

4、在超级循环中调用该函数,并传入参数0x22,例如:

代码语言:javascript
复制
void main(void)
{
    ...
    break_test(0x22);
    ...
}

5、编译并运行,观察输出:

分析代码不难发现,针对输入0x22,我们会从do{}while(0); 结构中跳出,并继续执行后续的代码,也就是打印“\tYou should see this ”,因此一个可能的输出结果是:

代码语言:javascript
复制
entering switch...
        Input is 0x22   You should see this
leave switch...

然而,我们实际观测到的是:

6、修改优化等级为 -O3 -Osize(如图所示,只要去掉 Optimize for time前面的勾选就行了),编译并运行,观察输出:

可以发现,代码中 do{}while() 结构内部的break被错误的当作了switch的break,从而跳过了 do{}while() 结构后面的代码。通过修改优化等级到-O3 -Osize或者是-O2 -Otime都可以避开这一问题。那么,这一问题是否严重呢?我觉得我要手动@一下所有使用protoThread和所有使用switch状态机的童鞋们,就问你们慌不慌

【玄学说法】“状态机好像容易跑飞……我也不知道是怎么回事,代码逻辑没问题啊?”;“高优先级下生成的代码不可靠!”;“switch里面的break和for以及do while的break究竟怎么用?我好方”;“我遇到一个bug,你来看看”,“我什么都没改啊,换个优化等级就对了……”,

【实际情况】编译器bug没的洗……但是bug就是bug,不要怀疑人生,不要怀疑自己所学的语法,发现bug有条件的话请及时报告。


【后记】

其实按道理说,这种bug应该非常明显,不至于被留到最后一个版本,仔细想想,至少有以下几种可能:

  • 这是 Arm Compiler 5.06u6 从 5.06u5 升级过程中引入的——正可谓拔出萝卜带出泥。可惜实际情况并不是这样的。有兴趣的朋友们可以去测试下老版本;
  • 大部分用户对C语法掌握情况不佳,基本处于模棱两可的状况;遇到类似情况不会用一个严谨的态度首先去确认正确的语法及行为;在坚持正确语法的情况下分析问题,从而判断出这是一个编译器错误;
  • 大部分用户不敢用最高的-O3 -Otime优化;
  • 大部分开最高优化的用户关心的主要是代码尺寸,从而恰好避开了这个问题;
  • 大部分用户没空去纠结这一问题;
  • 大部分用户遇到这类问题后,默默的选了-O0……
  • 大部分用户相信玄学……
  • 少部分牛人发现问题后懒得报告……

“大人,时代变了”

最后,欢迎大家尽早投入到Arm Compiler 6、IAR、GCC的怀抱……

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-05-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Mculover666 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档