"); //-->
在使用 KEIL 调试时,可能遇到很多莫名其妙的事情,比如有些位置无法断点调试,有些变量无法查看,很多人第一反应就是:是不是编译器优化级别太高导致的?
但是当你真正去查看编译级别时,发现已经是最低优化级别了。
编译优化表示:俺不背这个锅!
那么这又是怎么回事?
问题一:为什么有些地方无法打断点?
要搞清这个问题,我们首先要知道的是,调试器通过什么来确定哪些地方可以打断点,哪些地方不可以打断点?
相信有经验的道友已经想到了,就是通过 axf 文件。
很多资料都会告诉你,axf 文件除了代码之外,还包含了调试信息,那么这些调试信息又是什么?
其中一点就是 C 源码和汇编之间的对应关系。
只有当调试器(MDK)加载了这个axf文件,它才能知道哪些地方可以打断点,这个断点位置和C语言与汇编之间又有怎样的联系。
所以MDK 每次进入调试模式时,除了会下载代码到单片机中,同时还会加载 axf 文件到调试器,从而在源码级别进行调试。
那么回到原来的问题,哪些地方可以打断点呢?
看到左边的灰色部分了吧,只有灰色部分才是可以打断点位置,其他地方调试器并不承认有执行代码。
由此,我们可以通过这点确定一个宏是否处于开启状态。
比如一个宏打印 LOG(),如果打印开启的话,那么旁边一定是深灰色的,否则说明这行没有代码可以执行。
同时我们也可以由此确定你当前的 axf 文件是否是最新的。
比如有段代码修改了,但你进入调试模式后发现灰色部分和实际不一致,比如像这样:
那你要做的事情,首先就是编译 –> 下载。其次才是查看你的编译优化级别是否正确。
编译是为了将修改更新到 axf 文件中,下载是为了更新单片机的代码,之后进入调试模式时,单片机的代码和新加载的 axf 文件也就对应上了。
当然为了简单,鱼鹰一般的做法是直接 编译 –> 调试。当编译完之后,因为 MDK 检测到 axf 文件已经更新,所以会自动重新下载新代码到单片机中(这个功能是默认配置,当然也可以不下载),之后自动加载新 axf 文件到调试器,同时进入调试模式。
有些时候,你会发现能很快进入调试模式,就是因为调试器检测到 axf 文件没有过更新,所以也就不会自动下载了,这样就节省了很多时间。
所以这个锅,很可能就是因为修改了代码而忘记编译导致,该你自己背。
问题二:为什么有些变量无法通过 watch 查看?
真的是因为优化级别太高导致的吗?
遇到这种情况,首先看看你的代码是不是太简单了。
因为这个函数代码很简单,局部变量只有一个 temp(同时不需要对这个变量取地址操作),而空闲寄存器有很多,所以编译器直接将这个变量分配到寄存器中,这样这个 temp 变量就是 R4 寄存器,这样可以加快运行速度。
所以,这个锅也不能由编译优化来背,只能说是编译器的正常行为,只是你不了解罢了。
而当你的函数很复杂时(或者明确对局部变量进行取址操作),编译器就不得不将一些局部变量存放在栈中,这样你也就能像全局变量一样可以获取到局部变量的地址了。
不过MDK还是很智能了,在这个例子中,watch 窗口 可以查看 temp 的值,但程序离开了这个函数,这个值必定是无法再查看了,不信可以试试。
以上就是鱼鹰要分享的知识点,希望对各位道友有所帮助,下期再见。
*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。