許多計算機系統對數據類型的合法地址做了一些限制,要求某種數據類型對象的地址必須是某個值K(2,4,8)的倍數,這種堆積限制簡化形成了處理器和存儲器系統之間接口的硬件設計,總之就是為了方便高效的讀取數據,於是就有了數據對齊。
struct S1 { char k; double i; char c; };
Sizeof(S1)的值為24,而不是10,其原因就是數據對齊,如果是連續的存每個字段的值,那么double類型的i就可能分配在兩個8字節的存儲器塊中,那么可能就要執行兩次存儲器訪問,而現在的內存分配至這樣的,k,i,c都占用8個字節,這樣訪問1次存儲器就能得到double類型的i的值。k后面會有7個字節被浪費掉,也就是說i的偏移量是8,同樣的c后面有7個字節被浪費掉,盡管它后面沒有任何字段。這樣顯然太浪費內存了。如果我們將i和c的位置交換一下得到如下struct S2:
struct S2 { char k; char c; double i; };
現在Sizeof(S2)的值為16,而不是10也不是24。為了方便取出struct中最長的字段,即方便一次性讀出,這個最長的字段前面和后面的字段所占的長度都必須是它的倍數,在這里就是double的長度8的倍數。而k所占的長度加c所占的長度為2,小於8,所以k和c的內存是連續的,c后面接着的是6個空白字節然后就是i所占的8個字節。我想你會有這樣的疑問:為什么不直接把S1編譯成S2?我只能說我也不知道,但有一個類似的情況就是:在類的初始化列表中,先定義的字段先初始化。那么在這里先定義的先分配內存, 還有就是struct根本沒有產生多與的東西,來區分每個字段,要是編譯器把他們的內存結果重組了,它又怎么知道自己讀的是哪個字段呢。以上幾句只是阿漢的個人理解,沒有任何證明。
有了上面的解釋說明,在看一些簡單的struct所需的內存就容易了。
struct S3 { char k; int c; double i; };
Sizeof(S3):16,k與c連續,c后面3個字節空白,緊接着i占8個字節,共16個字節。
struct S4 { S3 a; int i[5]; };
那么sizeof(S4)的值為多少呢?40,a占16個字節,i占24個字節。a占16個字節我們是知道的,為什么int i[5]占24個字節,而不是20個字節呢,還是因為數據對齊,因為S3中的double i占8個字節,那么i占用的字節長度就一定是8的倍數,所以int i[5]占24個字節,而不是20個字節,如果S4中i的定義是int i[4],則i占16個字節,大家都沒話說,沒有疑問。
同樣的S4中的所有元素都是連續(會出現因為數據的長度不同而出現間隙空白),S4中的元素也會遵守數據對齊原則,其實我們可以把S4看成如下的樣子:
struct S4 { char k; int c; double i; int i[5]; };
這樣就好理解多了。
如果S3和S4的樣子如下
struct S3 { char k; int c; int i; }; struct S4 { S3 a[2]; double i[5]; };
sizeof(S4)等於多少呢?
作者:陳太漢