編譯優(yōu)化:這些鍋俺不背!
在使用 KEIL 調(diào)試時,可能遇到很多莫名其妙的事情,比如有些位置無法斷點調(diào)試,有些變量無法查看,很多人第一反應(yīng)就是:是不是編譯器優(yōu)化級別太高導(dǎo)致的?
但是當(dāng)你真正去查看編譯級別時,發(fā)現(xiàn)已經(jīng)是最低優(yōu)化級別了。
編譯優(yōu)化表示:俺不背這個鍋!
那么這又是怎么回事?
問題一:為什么有些地方無法打斷點?
要搞清這個問題,我們首先要知道的是,調(diào)試器通過什么來確定哪些地方可以打斷點,哪些地方不可以打斷點?
相信有經(jīng)驗的道友已經(jīng)想到了,就是通過 axf 文件。
很多資料都會告訴你,axf 文件除了代碼之外,還包含了調(diào)試信息,那么這些調(diào)試信息又是什么?
其中一點就是 C 源碼和匯編之間的對應(yīng)關(guān)系。
只有當(dāng)調(diào)試器(MDK)加載了這個axf文件,它才能知道哪些地方可以打斷點,這個斷點位置和C語言與匯編之間又有怎樣的聯(lián)系。
所以MDK 每次進(jìn)入調(diào)試模式時,除了會下載代碼到單片機中,同時還會加載 axf 文件到調(diào)試器,從而在源碼級別進(jìn)行調(diào)試。
那么回到原來的問題,哪些地方可以打斷點呢?
看到左邊的灰色部分了吧,只有灰色部分才是可以打斷點位置,其他地方調(diào)試器并不承認(rèn)有執(zhí)行代碼。
由此,我們可以通過這點確定一個宏是否處于開啟狀態(tài)。
比如一個宏打印 LOG(),如果打印開啟的話,那么旁邊一定是深灰色的,否則說明這行沒有代碼可以執(zhí)行。
同時我們也可以由此確定你當(dāng)前的 axf 文件是否是最新的。
比如有段代碼修改了,但你進(jìn)入調(diào)試模式后發(fā)現(xiàn)灰色部分和實際不一致,比如像這樣:
那你要做的事情,首先就是編譯 –> 下載。其次才是查看你的編譯優(yōu)化級別是否正確。
編譯是為了將修改更新到 axf 文件中,下載是為了更新單片機的代碼,之后進(jìn)入調(diào)試模式時,單片機的代碼和新加載的 axf 文件也就對應(yīng)上了。
當(dāng)然為了簡單,魚鷹一般的做法是直接 編譯 –> 調(diào)試。當(dāng)編譯完之后,因為 MDK 檢測到 axf 文件已經(jīng)更新,所以會自動重新下載新代碼到單片機中(這個功能是默認(rèn)配置,當(dāng)然也可以不下載),之后自動加載新 axf 文件到調(diào)試器,同時進(jìn)入調(diào)試模式。
有些時候,你會發(fā)現(xiàn)能很快進(jìn)入調(diào)試模式,就是因為調(diào)試器檢測到 axf 文件沒有過更新,所以也就不會自動下載了,這樣就節(jié)省了很多時間。
所以這個鍋,很可能就是因為修改了代碼而忘記編譯導(dǎo)致,該你自己背。
問題二:為什么有些變量無法通過 watch 查看?
真的是因為優(yōu)化級別太高導(dǎo)致的嗎?
遇到這種情況,首先看看你的代碼是不是太簡單了。
因為這個函數(shù)代碼很簡單,局部變量只有一個 temp(同時不需要對這個變量取地址操作),而空閑寄存器有很多,所以編譯器直接將這個變量分配到寄存器中,這樣這個 temp 變量就是 R4 寄存器,這樣可以加快運行速度。
所以,這個鍋也不能由編譯優(yōu)化來背,只能說是編譯器的正常行為,只是你不了解罷了。
而當(dāng)你的函數(shù)很復(fù)雜時(或者明確對局部變量進(jìn)行取址操作),編譯器就不得不將一些局部變量存放在棧中,這樣你也就能像全局變量一樣可以獲取到局部變量的地址了。
不過MDK還是很智能了,在這個例子中,watch 窗口 可以查看 temp 的值,但程序離開了這個函數(shù),這個值必定是無法再查看了,不信可以試試。
以上就是魚鷹要分享的知識點,希望對各位道友有所幫助,下期再見。
*博客內(nèi)容為網(wǎng)友個人發(fā)布,僅代表博主個人觀點,如有侵權(quán)請聯(lián)系工作人員刪除。
電路圖符號相關(guān)文章:電路圖符號大全