引言
先看下面這段程序
運行結果(輸出)是:
sizeof(C):12
sizeof(D):8
2個結構體,成員個數,成員類型都一樣,不同的只是成員的順序,最終sizeof的結果卻不相同。要解釋這個問題就需要說明內存對齊。
爲什麼要對齊
爲了能使CPU對變量進行高效快速的訪問,變量的起始地址應該具有某些特性,即所謂的"對齊"。
基本概念
數據類型自身的對齊值: 一般地(32位機),對於char型數據,其自身對齊值爲1,對於short型爲2,對於int,float,double類型,其自身對齊值爲4,單位字節。
結構體或者類的自身對齊值: 其成員中自身對齊值最大的那個值。
指定對齊值: #pragma pack (value)時的指定對齊值value。
數據成員、結構體和類的有效對齊值: 自身對齊值和指定對齊值中小的那個值。
因此,32位機中,#pragma pack(16)是沒有意義的(long long的對齊值爲8),原因是有效對齊值取自身對齊和指定對齊中小的那個值。
另外,不同的編譯器有默認的指定對齊值(這也是爲什麼同一個結構在不同編譯器中sizeof結果不同的原因),如VS系列默認對齊方式爲#pragma pack(8),也就是說VS默認以8個字節對齊(如果結構體中某個成員的sizeof大於8)。VC6.0中可以這樣修改默認的指定對齊方式:
[Project]|[Settings],c/c++選項卡Category的Code Generation選項的Struct Member Alignment中修改。
顯然,編碼時,可以通過#pragma動態地修改結構體的指定對齊值。
對齊原則
對齊方式影響結構體成員在結構體中的偏移,不妨設編譯器指定對齊參數爲n,對於結構體中的某一成員item,它相對於結構首地址的實際字節對齊數目X應該滿足以下規則:
X = min ( n, sizeof(item) )
例如,對於結構體 struct A {char a; int b};
當位於32位系統,n=8時:
a的偏移爲0,
b的偏移爲4,中間填充了3個字節, b的X爲4;
當位於32位系統,n=2時:
a的偏移爲0,
b的偏移爲2,中間填充了1個字節,b的X爲2;
再如,對於結構體 struct B{int a;char b;char c;int d};
當位於32位系統,n=8時:
a 的偏移爲0,
b的偏移爲4,
c的偏移爲5,
d的偏移爲8,中間填充了2個字節
當位於32位系統,n=2時:
a 的偏移爲0,
b的偏移爲4,
c的偏移爲5,
d的偏移爲6
最後,結構的長度必須爲所用過的所有對齊參數的整數倍,不夠就補空字節。