關於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其它相關文章!

推薦閱讀: