编译优化:这些锅俺不背!

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

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

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

那么这又是怎么回事?

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


1.做备忘|GD32 Arm MCU物联网开发者线上课程不容错过!

2.学嵌入式该不该参加培训?

3.苹果M1预示着RISC-V的崛起?

4.关于RISC-V启动部分的思考~

5.你可能不了解的ARM处理异常之道!

6.有人说,这几门语言要被淘汰了!

免责声明:本文系网络转载,版权归原作者所有。如涉及作品版权问题,请与我们联系,我们将根据您提供的版权证明材料确认版权并支付稿酬或者删除内容。

猜你喜欢

转载自blog.csdn.net/DP29syM41zyGndVF/article/details/111877802