新闻  |   论坛  |   博客  |   在线研讨会
编译优化:这些锅俺不背!
鱼鹰谈单片机 | 2021-01-01 11:37:43    阅读:510   发布文章

在使用 KEIL 调试时,可能遇到很多莫名其妙的事情,比如有些位置无法断点调试,有些变量无法查看,很多人第一反应就是:是不是编译器优化级别太高导致的?

但是当你真正去查看编译级别时,发现已经是最低优化级别了。

编译优化表示:俺不背这个锅!

那么这又是怎么回事?

问题一:为什么有些地方无法打断点?

要搞清这个问题,我们首先要知道的是,调试器通过什么来确定哪些地方可以打断点,哪些地方不可以打断点?

相信有经验的道友已经想到了,就是通过 axf 文件。

很多资料都会告诉你,axf 文件除了代码之外,还包含了调试信息,那么这些调试信息又是什么?

其中一点就是 C 源码和汇编之间的对应关系。

只有当调试器(MDK)加载了这个axf文件,它才能知道哪些地方可以打断点,这个断点位置和C语言与汇编之间又有怎样的联系。

所以MDK 每次进入调试模式时,除了会下载代码到单片机中,同时还会加载 axf 文件到调试器,从而在源码级别进行调试。

那么回到原来的问题,哪些地方可以打断点呢?

5.png

看到左边的灰色部分了吧,只有灰色部分才是可以打断点位置,其他地方调试器并不承认有执行代码。

由此,我们可以通过这点确定一个宏是否处于开启状态。

比如一个宏打印 LOG(),如果打印开启的话,那么旁边一定是深灰色的,否则说明这行没有代码可以执行。

同时我们也可以由此确定你当前的 axf 文件是否是最新的。

比如有段代码修改了,但你进入调试模式后发现灰色部分和实际不一致,比如像这样:

4.png

那你要做的事情,首先就是编译 –> 下载。其次才是查看你的编译优化级别是否正确。

编译是为了将修改更新到 axf 文件中,下载是为了更新单片机的代码,之后进入调试模式时,单片机的代码和新加载的 axf 文件也就对应上了。

当然为了简单,鱼鹰一般的做法是直接 编译 –> 调试。当编译完之后,因为 MDK 检测到 axf 文件已经更新,所以会自动重新下载新代码到单片机中(这个功能是默认配置,当然也可以不下载),之后自动加载新 axf 文件到调试器,同时进入调试模式。

3.png

有些时候,你会发现能很快进入调试模式,就是因为调试器检测到 axf 文件没有过更新,所以也就不会自动下载了,这样就节省了很多时间。

所以这个锅,很可能就是因为修改了代码而忘记编译导致,该你自己背。

问题二:为什么有些变量无法通过 watch 查看?

真的是因为优化级别太高导致的吗?

遇到这种情况,首先看看你的代码是不是太简单了。

2.png

因为这个函数代码很简单,局部变量只有一个 temp(同时不需要对这个变量取地址操作),而空闲寄存器有很多,所以编译器直接将这个变量分配到寄存器中,这样这个 temp 变量就是 R4 寄存器,这样可以加快运行速度。

1.png

所以,这个锅也不能由编译优化来背,只能说是编译器的正常行为,只是你不了解罢了。

而当你的函数很复杂时(或者明确对局部变量进行取址操作),编译器就不得不将一些局部变量存放在栈中,这样你也就能像全局变量一样可以获取到局部变量的地址了。

不过MDK还是很智能了,在这个例子中,watch 窗口 可以查看 temp 的值,但程序离开了这个函数,这个值必定是无法再查看了,不信可以试试。

以上就是鱼鹰要分享的知识点,希望对各位道友有所帮助,下期再见。

*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
推荐文章
最近访客