關於C++中由於字節對齊引起內存問題定位分析
最近遇到瞭一個奇怪的問題,在創建對象時程序異常退出,具體地,在構造函數中訪問類中最後一個成員變量時,程序異常退出。
問題定位
查看代碼,發現該類中有一個結構體數組,該結構體在類的外面聲明,用 #pragma pack(push,1) 設置瞭一字節對齊方式,而類不在這個作用范圍內,所以是按照默認字節對齊方式的。懷疑該問題是因為,類的字節對齊方式和類中的結構體字節方式不同引起的。但這從理論方面解釋不通。
繼續定位,在創建對象之前用sizeof打印類的大小,再在類的構造函數中打印類的大小。發現這兩個大小居然不同。這證實瞭的確與字節對齊有關,創建對象之前和在構造函數中,兩邊選擇的字節對齊方式不同,導致計算類的大小不同。
但是為什麼這兩個地方的字節對齊方式不同呢?
當把該類也使用 #pragma pack(push,1) 設置字節對齊方式之後,類的大小又變得相同瞭。大膽猜測,由於 #pragma pack(push, 1) 是一種棧的結構,可能有某個文件中,設置瞭字節對齊方式之後,沒有用 #pragma pack(pop) 恢復。
查找全局文件,的確找到瞭一個文件存在這樣的問題,當把 #pragma pack(pop) 後加上後,問題解決。
問題模型
我將這個問題簡化成下面這樣,可以幫助大傢更好地理解。
CA.h,CA類的聲明,模擬隻push,沒pop的文件
#ifndef CA_H #define CA_H #include <iostream> using namespace std; #pragma pack(push, 1) class CA { int a; char b; }; #endif
CB.h,CB類的聲明。St結構體設置一字節對齊方式,CB類使用默認字節對齊方式。
#ifndef CB_H #define CB_H #include <iostream> using namespace std; #pragma pack(push,1) struct St { int a1; int a2; int a3; char a4; char a5; }; #pragma pack(pop) class CB { public: CB(); int a1; int a2; int a3; char a4; char a5; St a6[10]; bool a7; }; #endif
CB.cpp,CB類的實現。
#include "CB.h" #include <iostream> using namespace std; CB::CB() { cout << "constructor: sizeof(CB) = "; cout << sizeof(CB) << endl; }
main.cpp,用於創建CB對象
#include "CA.h" #include "CB.h" #include <iostream> using namespace std; int main() { cout << "main: sizeof(CB) = "; cout << sizeof(CB) << endl; CB *pCB = new CB; }
編譯上述文件並執行,可以得到下面的結果:
main: sizeof(CB) = 155
constructor: sizeof(CB) = 156
可以看到,兩處計算的類的大小是不同的。在main函數裡,分配瞭155字節的空間,而在構造函數中卻認為有156字節的空間,當訪問最後一字節時,程序出現瞭踩內存。
問題分析
為什麼main.cpp和CB.cpp認為CB的字節對齊方式不同呢?
這主要還是因為main.cpp包含瞭CA.h,CA.h在main.cpp中展開,CB.h也展開,CA.h中設置的一字節對齊方式,影響到瞭CB類的聲明,當編譯main.cpp時,CB使用一字節對齊方式。
而CB.h沒有包含CA.h,當編譯CB.cpp時,並沒有受到CA.h的影響,CB使用默認字節對齊方式。
以上就是關於C++中由於字節對齊引起內存問題定位分析的詳細內容,更多關於c++字節對齊內存問題的資料請關註WalkonNet其它相關文章!