前述
大家在平常的編程過程應該會碰到各種奇葩的問題吧,反正我最近是碰到了一次,再此跟大家分享一下。事情的原因是我在程序中增加了一個變量,然后就會導致程序每次都會進入異常。
示例代碼
我將代碼簡化了,使用兩個模塊來演示這個問題。第一個模塊是Dev模塊。
下面是Dev模塊的頭文件,Dev結構體中有一個數組。
#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,相關數據結構如下:
#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_變量以及與之相關的業務會導致每次調試目標板都會進入異常。
嘗試解決異常問題
根據調試情況看,每次都會出現異常,說明是個小問題。就怕偶爾出現異常,不容易復現。
思路應該非常清晰,出現異常時候查看LR寄存器的值,LR寄存器主要有兩個功能。
保存子程序返回地址。使用BL或BLX時,跳轉指令自動把返回地址放入r14中
當異常發生時,異常模式的R14用來保存異常返回地址
根據LR寄存器的值,從而定位到是執行DevInit(&c_this->iic_)函數中的memset導致的。
第一反應是DevInit中傳入的對象可能為空,操作了非法內存才導致的錯誤。于是又重新調試了一遍,發現DevInit中對象的地址并不為空,而且就是等于實體對象中設備的地址。
這一刻我陷入了深深的自我懷疑,memset難道不是這樣用的?難道不是傳入一個地址,清0,然后sizeof(DevManage)就完事了?
我這代碼怎么會出錯,memset就是這樣用的,天王老子來我也是對的,這樣的心理是不是也深度還原了碰到問題時的你們。
如果是你,該如何繼續...
救命稻草
有人說,匯編是最后的救命稻草。那我也嘗試抓住這根稻草,出現問題時如下圖:
問題主要出現紅色箭頭指向的這一行,經過查詢資料得知_aeabi_memclr4是一個用于ARM嵌入式系統的函數,用于將內存區域清零。函數名中的"_a"表示該函數符合ARM嵌入式應用二進制接口(Embedded Application Binary Interface,EABI)規范。在調用_aeabi_memclr4時,需要確保傳入的內存地址是四字節對齊的。再看圖片中的對象地址為0x200001BD,剛好比四字節對齊地址0x200001BC多了一個字節。
再回頭看DevManage對象,這里使用了偽指令#pragma pack(1)讓內存分配進行單字節對齊。因為Dev對象是按照四字節對齊的,緊接著引入了新的成員num_占用一個字節。所以導致iic_對象的地址相對于未增加變量之前的地址偏移了一個字節,導致不是四字節對齊的了,從而引發了錯誤。
就示例中的代碼而言,只需要把強制DevManage對象單字節對齊的功能刪除即可解決問題,因為默認情況下是四字節對齊的。
成員分配
由于#pragma pack(1)具有作用域限制,這里其實只是對num_變量做了單字節對齊的限制,而并沒有對Dev對象的內存分配起到限制作用,Dev對象仍然是按照4字節對齊的(默認值),所以Dev對象的所占用的長度一定是101*4=404字節。而整個DevManager對象的大小就101 * 4 + 1 + 101 * 4 = 809字節,成員分配如下圖所示。
最后
到最后在拋出一個問題,對于上述的代碼在vscode中使用gcc編譯執行為何沒有問題?
審核編輯:湯梓紅
-
模塊
+關注
關注
7文章
2736瀏覽量
47791 -
編程
+關注
關注
88文章
3640瀏覽量
94032 -
程序
+關注
關注
117文章
3798瀏覽量
81457 -
變量
+關注
關注
0文章
613瀏覽量
28475
原文標題:加個變量,程序崩了
文章出處:【微信號:typedef,微信公眾號:typedef】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
數據波形中的一個數據異常點分析
分析一個關于STM32 芯片異常復位的經典案例!
STM32局部變量過大導致棧溢出怎么去解決呢
XDATA定義變量后程序異常的原因?怎么解決?
多變量水質參數時間異常事件檢測算法
![多<b class='flag-5'>變量</b>水質參數時間<b class='flag-5'>異常</b>事件檢測算法](https://file.elecfans.com/web2/M00/49/77/poYBAGKhwLmAORIIAAAVJTycntk035.jpg)
評論