轉載於QuitePig的專欄
一個結構體變量定義完之后,其在內存中的存儲並不等於其所包含元素的寬度之和
1:元素為基本數據類型的結構體
例一:

例一中的結構體變量S1定義之后,經測試,會發現:
sizeof(S1)= 16,sizeof(S1.a) = 1,sizeof(S1.b) = 4, sizeof(S1.c) = 8
原則一:結構體中元素是按照定義順序一個一個放到內存中去的,但並不是緊密排列的。
從結構體存儲的首地址開始,每一個元素放置到內存中時,它都會認為內存是以它自己的大小
來划分的,因此元素放置的位置一定會在自己寬度的整數倍上開始(以結構體變量首地址為0計算)
比如此例,首先系統會將字符型變量a存入第0個字節(相對地址,指內存開辟的首地址);
然后在存放整形變量b時,會以4個字節為單位進行存儲,由於第一個四字節模塊已有數據,
因此它會存入第二個四字節模塊,也就是存入到4~8字節;
同理,存放雙精度實型變量c時,由於其寬度為8,其存放時會以8個字節為單位存儲,
也就是會找到第一個空的且是8的整數倍的位置開始存儲。
此例中,由於頭一個8字節模塊已被占用,所以將c存入第二個8字節模塊。整體存儲示意圖如圖1所示:
考慮另外一個實例,例二:
struct X { char a; double b; int c; }S2;
將double型的變量和int型的變量互換位置。測試程序不變,測試結果卻截然不同,sizeof(S2)=24,
不同於我們按照原則一計算出的8+8+4=20,這就引出了我們的第二原則。
原則二:在經過第一原則分析后,檢查計算出的存儲單元是否為所有元素中最寬的元素的長度的整數倍,
是,則結束;若不是,則補齊為它的整數倍。
例二中,我們分析完后的存儲長度為20字節,不是最寬元素長度8的整數倍,因此將它補齊到8的整數倍,
也就是24。這樣就沒問題了。其存儲示意圖如圖2所示。
2:元素包含指針類型的的結構體
原則:只要記住指針本身所占的存儲空間是4個字節就行了,而不必看它是指向什么類型的指針
struct X struct Y struct Z
{ { {
char *a; int *b; double *c;
}; }; };
經測試,可知sizeof(X)、sizeof(Y)和sizeof(Z)的值都為4。
3:元素包含其他結構體類型的的結構體
struct X { char a; int b; double c; }; struct Y { char a; X b; };
經測試,可知sizeof(X)=16,sizeof(Y)=24。
即計算Y的存儲長度時,在存放第二個元素b時的初始位置是在double型的長度8的整數倍處,而非16的整數倍處,
即系統為b所分配的存儲空間是第8~23個字節。
如果將Y的兩個元素char型的a和X型的b調換定義順序,則系統為b分配的存儲位置是第0~15個字節,
為a分配的是第16個字節,加起來一共17個字節,不是最長基本類型double所占寬度8的整數倍,
因此要補齊到8的整數倍,即24。測試后可得sizeof(Y)的值為24。
由於結構體所占空間與其內部元素的類型有關,而且與不同類型元素的排列有關,因此在定義結構體時,
在元素類型及數量確定之后,我們還應該注意一下其內部元素的定義順序。