C++ struct記憶體對齊
•小試牛刀
我們自定義兩個結構體 A 和 B:
struct A { char c1; char c2; int i; double d; }; struct B { char c1; int i; char c2; double d; };通過定義我們可以看出,結構體 A 和 B 擁有相同的成員,只不過在排列順序上有所不同;
眾所周知,char 型別佔 1 個位元組,int 型別佔 4 個位元組,double 型別佔 8 個位元組;
那麼,這兩個結構體所佔記憶體空間大小為多少呢?佔用的空間是否相同?
空口無憑,讓我們通過編譯器告訴我們答案(我使用的是 VS2022,X86)。
在 main() 函式中輸出如下語句:
int main() { printf("結構體A所佔記憶體大小為:%d\n", sizeof(A)); printf("結構體B所佔記憶體大小為:%d\n", sizeof(B)); return 0; }執行之前,先盲猜一個結果:
sizeof(A) = sizeof(B) = sizeof(c1)+sizeof(c2)+sizeof(i)+sizeof(d) = 1+1+4+8 = 14;
到底對不對呢?讓我們來看看執行結果:
amazing~~
竟然一個都沒猜對,這究竟是怎麼回事呢?
下面開始進入今天的主題——struct 記憶體對齊。
•記憶體對齊
一種提高記憶體訪問速度的策略,CPU 在訪問未對齊的記憶體可能需要經過兩次的記憶體訪問,而經過記憶體對齊一次就可以了。
假定現在有一個 32 位處理器,那這個處理器一次性讀取或寫入都是四位元組。
假設現在有一個 32 位處理器要讀取一個 int 型別的變數,在記憶體對齊的情況下,處理器是這樣進行讀取的:
那如果資料儲存沒有按照記憶體對齊的方式進行的話,處理器就會這樣進行讀取:
對比記憶體對齊和記憶體沒有對齊兩種情況我們可以明顯地看到,在記憶體對齊的情況下,取得這個 int型 變數只需要經過一次定址(0~3);
但在記憶體沒有對齊的情況下,取得這個 int型 變數需要經過兩次的定址(0~3 和 4~7),然後再合併資料。
通過上述的分析,我們可以知道記憶體對齊能夠提升效能,這也是我們要進行記憶體對齊的原因之一。
•記憶體對齊的原則
- 對於結構體的各個成員,第一個成員的偏移量是 0,排列在後面的成員其當前偏移量必須是當前成員型別的整數倍。
- 結構體內所有資料成員各自記憶體對齊後,結構體本身還要進行一次記憶體對齊,保證整個結構體佔用記憶體大小是結構體內最大資料成員的最小整數倍。
- 如程式中有 #pragma pack(n)預編譯指令,則所有成員對齊以 n位元組 為準(即偏移量是n的整數倍),不再考慮當前型別以及最大結構體內型別。
下面通過圖示來分享一下我的理解,為方便理解,我將記憶體地址的編號設定為 0~24。
對與結構體 A:
- 第一個成員 c1 假設放置到 0 位置
- 第二個成員 c2 要偏移