前述
大家在平常的編程過程應該會碰到各種奇葩的問題吧,反正我最近是碰到了一次,再此跟大家分享一下。事情的原因是我在程序中增加了一個變量,然后就會導致程序每次都會進入異常。
示例代碼
我將代碼簡化了,使用兩個模塊來演示這個問題。第一個模塊是Dev模塊。
下面是Dev模塊的頭文件,Dev結構體中有一個數(shù)組。
#include#include typedefstruct{ inta_[100]; charb_; }Dev; voidDevInit(Dev*c_this);
下面是Dev模塊的源文件代碼,里面只有一個memset。
#include"Dev.h" voidDevInit(Dev*c_this){ memset(c_this,0,sizeof(Dev)); }
第二個模塊是DevManager,相關數(shù)據(jù)結構如下:
#include"Dev.h" #pragmapack(1) typedefstruct{ Devuart_; charnum_;//Addingthisvariablecausesacrash Deviic_; }DevManage; #pragmapack() DevManagedev_manage; voidDevManagerInit(void){ DevManage*c_this=&dev_manage; memset(c_this,0,sizeof(DevManage)); DevInit(&c_this->uart_); DevInit(&c_this->iic_); }
DevManage結構體包含uart以及iic設備,以及我新加入的一個num_變量,由于新增了num_變量以及與之相關的業(yè)務會導致每次調(diào)試目標板都會進入異常。
嘗試解決異常問題
根據(jù)調(diào)試情況看,每次都會出現(xiàn)異常,說明是個小問題。就怕偶爾出現(xiàn)異常,不容易復現(xiàn)。
思路應該非常清晰,出現(xiàn)異常時候查看LR寄存器的值,LR寄存器主要有兩個功能。
保存子程序返回地址。使用BL或BLX時,跳轉指令自動把返回地址放入r14中
當異常發(fā)生時,異常模式的R14用來保存異常返回地址
根據(jù)LR寄存器的值,從而定位到是執(zhí)行DevInit(&c_this->iic_)函數(shù)中的memset導致的。
第一反應是DevInit中傳入的對象可能為空,操作了非法內(nèi)存才導致的錯誤。于是又重新調(diào)試了一遍,發(fā)現(xiàn)DevInit中對象的地址并不為空,而且就是等于實體對象中設備的地址。
這一刻我陷入了深深的自我懷疑,memset難道不是這樣用的?難道不是傳入一個地址,清0,然后sizeof(DevManage)就完事了?
我這代碼怎么會出錯,memset就是這樣用的,天王老子來我也是對的,這樣的心理是不是也深度還原了碰到問題時的你們。
如果是你,該如何繼續(xù)...
救命稻草
有人說,匯編是最后的救命稻草。那我也嘗試抓住這根稻草,出現(xiàn)問題時如下圖:
問題主要出現(xiàn)紅色箭頭指向的這一行,經(jīng)過查詢資料得知_aeabi_memclr4是一個用于ARM嵌入式系統(tǒng)的函數(shù),用于將內(nèi)存區(qū)域清零。函數(shù)名中的"_a"表示該函數(shù)符合ARM嵌入式應用二進制接口(Embedded Application Binary Interface,EABI)規(guī)范。在調(diào)用_aeabi_memclr4時,需要確保傳入的內(nèi)存地址是四字節(jié)對齊的。再看圖片中的對象地址為0x200001BD,剛好比四字節(jié)對齊地址0x200001BC多了一個字節(jié)。
再回頭看DevManage對象,這里使用了偽指令#pragma pack(1)讓內(nèi)存分配進行單字節(jié)對齊。因為Dev對象是按照四字節(jié)對齊的,緊接著引入了新的成員num_占用一個字節(jié)。所以導致iic_對象的地址相對于未增加變量之前的地址偏移了一個字節(jié),導致不是四字節(jié)對齊的了,從而引發(fā)了錯誤。
就示例中的代碼而言,只需要把強制DevManage對象單字節(jié)對齊的功能刪除即可解決問題,因為默認情況下是四字節(jié)對齊的。
成員分配
由于#pragma pack(1)具有作用域限制,這里其實只是對num_變量做了單字節(jié)對齊的限制,而并沒有對Dev對象的內(nèi)存分配起到限制作用,Dev對象仍然是按照4字節(jié)對齊的(默認值),所以Dev對象的所占用的長度一定是101*4=404字節(jié)。而整個DevManager對象的大小就101 * 4 + 1 + 101 * 4 = 809字節(jié),成員分配如下圖所示。
最后
到最后在拋出一個問題,對于上述的代碼在vscode中使用gcc編譯執(zhí)行為何沒有問題?
審核編輯:湯梓紅
-
模塊
+關注
關注
7文章
2613瀏覽量
47010 -
編程
+關注
關注
88文章
3521瀏覽量
93268 -
程序
+關注
關注
115文章
3720瀏覽量
80357 -
變量
+關注
關注
0文章
607瀏覽量
28257
原文標題:加個變量,程序崩了
文章出處:【微信號:typedef,微信公眾號:typedef】歡迎添加關注!文章轉載請注明出處。
發(fā)布評論請先 登錄
相關推薦
評論