当前位置:首页 > 公众号精选 > 裸机思维

  编译器的智商似乎是很“诡异”的,我想大家对这个结论很少会有异议,无奈我们总归还是要去摸清它的脾气,谁让我们是苦逼的的程序员呢?外国有句老话说得好:要理解别人的想法,最好“穿别人的鞋”。

  和编译器同穿一双鞋,就是站在编译器的视角,尝试在保持原有代码逻辑的基础上优化代码,以获取更小的代码尺寸或者执行效率。接下来,我们首先看一个例子:

  //! 一个全局变量

  extern uint32_t g_wDemo;

  //! 有一个函数要用到这个全局变量

  void example(void)

  {

    uint32_t i = 0;

    for (; i < 10; i++) {

      g_wDemo |= 0x01;

    }

  }

  很显然,如果我们是编译器,重复将普通的全局变量BIT0置位100次这种傻事肯定要优化掉——做一次就够了嘛,别做无用功嘛!结果如下:

  //! 优化后的结果

  void example(void)

  {

    //uint32_t i = 0;

    //for (; i < 100; i++) {

      g_wDemo |= 0x01;

    //}

  }

  干得漂亮,我们继续,看下一个例子:

  //! 有一个函数要用到这个全局变量

  void example(void)

  {

    uint32_t i = 0;

    uint32_t wTemp;

    for (; i < 100; i++) {

      wTemp = g_wDemo ;

      //! 各类针对wTemp的只读操作

...

    }

  }

  这里怎么优化呢?我们注意到g_wDemo在循环中每次都要被读取,单看这个循环,明显只有针对g_wDemo的读取操作,而没有任何对g_wDemo的写入操作——换句话说,在这个循环里面g_wDemo是只读的,内容是不会被修改的!那为啥我每次都要重新读取一遍呢?浪费浪费!优化优化!

  //! 有一个函数要用到这个全局变量

  void example(void)

  {

    uint32_t i = 0;

    uint32_t wTemp = g_wDemo ; //! 刚开始的时候读一次就够了!!

    for (; i < 100; i++) {

      //! 各类针对wTemp的只读操作

...

    }

  }

——“恩,我们又一次拯救了世界。”

——“什么什么?你说我优化错了!”

——“什么?那个全局变量是有来头的?”

——“啥?这个全局变量不是普通的全局变量?你自己写成extern uint32_t g_wDemo,没看到什么特殊的啊?”

——“啥?是一个外设寄存器?那又如何?”

——“啥?这是一个GPIO的Toggle寄存器?每次置位都会取反对应IO?对其读取将获得IO的真实输入电平?”

#define g_wDemo (* (uint32_t *)GPIO_A_TOGGLE_ADDRESS)

——“谁管你!你告诉我这些了?你说,你什么地方告诉我这些了?你说阿!”

——“敢说我们做错了?敢冤枉老子!你找死哦!是你自己没说清楚,怪我咯!你说说你什么地方说过这个变量很重要?你说说什么地方告诉过我,每一次读写都有特别的意义?!”

——“什么?你以为我应该知道的?你不知道要加volatile么?你不给我提示,你让我猜阿!我怎么知道那个地址对应哪个寄存器?我怎么知道你脑子里想什么?!你知道这个全局变量是外设寄存器,我又不是你肚子里的蛔虫?老子辛辛苦苦的给你优化半天,你一个想当然 ‘以为我应该知道’ 就把责任都丢给我了?我凭什么应该知道?我要是能替你决定还要你做萨子!?”

#define g_wDemo (* (volatile uint32_t *)GPIO_A_TOGGLE_ADDRESS)

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
关闭