成員邊界對齊 pragma pack n

2021-04-24 02:57:55 字數 3978 閱讀 5312

intel、微軟等公司曾經出過一道類似的面試題:

1. #include

2. #pragma pack(8)

3. struct example1

4. ;

8. struct example2

9. ;

14. #pragma pack()

15. int main(int argc, char* argv)

16.

問程式的輸入結果是什麼?

答案是:816

4不明白?還是不明白?下面一一道來:

2.1 自然對界

struct是一種復合資料型別,其構成元素既可以是基本資料型別(如int、long、float等)的變數,也可以是一些復合資料型別(如array、struct、union等)的資料單元。對於結構體,編譯器會自動進行成員變數的對齊,以提高運算效率。預設情況下,編譯器為結構體的每個成員按其自然對界(natural alignment)條件分配空間。各個成員按照它們被宣告的順序在記憶體中順序儲存,第乙個成員的位址和整個結構的位址相同。

自然對界(natural alignment)即預設對齊方式,是指按結構體的成員中size最大的成員對齊。

例如:struct naturalalign

;在上述結構體中,size最大的是short,其長度為2位元組,因而結構體中的char成員a、c都以2為單位對齊,sizeof(naturalalign)的結果等於6;

如果改為:

struct naturalalign

;其結果顯然為12。

2.2指定對界

一般地,可以通過下面的方法來改變預設的對界條件:

· 使用偽指令#pragma pack (n),編譯器將按照n個位元組對齊;

· 使用偽指令#pragma pack (),取消自定義位元組對齊方式。

注意:如果#pragma pack (n)中指定的n大於結構體中最大成員的size,則其不起作用,結構體仍然按照size最大的成員進行對界。

例如:#pragma pack (n)

struct naturalalign

;#pragma pack ()

當n為4、8、16時,其對齊方式均一樣,sizeof(naturalalign)的結果都等於12。而當n為2時,其發揮了作用,使得sizeof(naturalalign)的結果為8。

在vc++ 6.0編譯器中,我們可以指定其對界方式(見圖1),其操作方式為依次選擇projetct > setting > c/c++選單,在struct member alignment中指定你要的對界方式。

圖1:在vc++ 6.0中指定對界方式

另外,通過__attribute((aligned (n)))也可以讓所作用的結構體成員對齊在n位元組邊界上,但是它較少被使用,因而不作詳細講解。

2.3 面試題的解答

至此,我們可以對intel、微軟的面試題進行全面的解答。

程式中第2行#pragma pack (8)雖然指定了對界為8,但是由於struct example1中的成員最大size為4(long變數size為4),故struct example1仍然按4位元組對界,struct example1的size為8,即第18行的輸出結果;

struct example2中包含了struct example1,其本身包含的簡單資料成員的最大size為2(short變數e),但是因為其包含了struct example1,而struct example1中的最大成員size為4,struct example2也應以4對界,#pragma pack (8)中指定的對界對struct example2也不起作用,故19行的輸出結果為16;

由於struct example2中的成員以4為單位對界,故其char變數c後應補充3個空,其後才是成員struct1的記憶體空間,20行的輸出結果為4。

struct size2;

上邊的好像有點問題,這個sizeof()的結果是24;

目前可以這樣算,1+4+4+8 = 17;求大於17的8的最小倍數,那麼就是24了。

(看了下邊的,知道怎麼回事了,上邊我說的錯了)

struct size2;  //最後整體偏移為24,可以整除8。

在c語言中,結構是一種復合資料型別,其構成元素既可以是基本資料型別(如int、long、float等)的變數,也可以是一些復合資料型別(如陣列、結構、聯合等)的資料單元。在結構中,編譯器為結構的每個成員按其自然對界(alignment)條件分配空間。各個成員按照它們被宣告的順序在記憶體中順序儲存,第乙個成員的位址和整個結構的位址相同。

例如,下面的結構各成員空間分配情況:

struct test

;結構的第乙個成員x1,其偏移位址為0,佔據了第1個位元組。第二個成員x2為short型別,其起始位址必須2位元組對界,因此,編譯器在x2和x1之間填充了乙個空位元組。結構的第三個成員x3和第四個成員x4恰好落在其自然對界位址上,在它們前面不需要額外的填充位元組。在test結構中,成員x3要求4位元組對界,是該結構所有成員中要求的最大對界單元,因而test結構的自然對界條件為4位元組,編譯器在成員x4後面填充了3個空位元組。整個結構所佔據空間為12位元組。

重要規則:

1,複雜型別中各個成員按照它們被宣告的順序在記憶體中順序儲存,第乙個成員的位址和整個型別的位址相同;

2,每個成員分別對齊,即每個成員按自己的方式對齊,並最小化長度;規則就是每個成員按其型別的對齊引數(通常是這個型別的大小)和指定對齊引數中較小的乙個對齊;

3,結構、聯合或者類的資料成員,第乙個放在偏移為0的地方;以後每個資料成員的對齊,按照#pragma pack指定的數值和這個資料成員自身長度兩個中比較小的那個進行;也就是說,當#pragma pack指定的值等於或者超過所有資料成員長度的時候,這個指定值的大小將不產生任何效果;

4,複雜型別(如結構)整體的對齊是按照結構體中長度最大的資料成員和#pragma pack指定值之間較小的那個值進行;這樣在成員是複雜型別時,可以最小化長度;

5,結構整體長度的計算必須取所用過的所有對齊引數的整數倍,不夠補空位元組;也就是取所用過的所有對齊引數中最大的那個值的整數倍,因為對齊引數都是2的n次方;這樣在處理陣列時可以保證每一項都邊界對齊;

如:class testb

;sizeof(testb)的值為12.

例子一:

#pragma pack(4)

class testb

;可見,此類實際占用的記憶體空間是9個位元組。根據規則5,結構整體的對齊是min( sizeof( int ), pack_value ) = 4,所以sizeof( testb ) = 12;

例子二:

#pragma pack(2)

class testb

;可見結果與例子一相同,各個成員的位置沒有改變,但是此時結構整體的對齊是min( sizeof( int ), pack_value ) = 2,所以sizeof( testb ) = 10;

例子三:

#pragma pack(4)

class testc

;整個類的實際記憶體消耗是5個位元組,整體按照min( sizeof( short ), 4 ) = 2對齊,所以結果是sizeof( testc ) = 6;

例子四:

struct test

;所以整個結構體的實際記憶體消耗是9個位元組,但考慮到結構整體的對齊是4個位元組,所以整個結構占用的空間是12個位元組。

例子五:

#pragma pack(8)

struct s1

;所以結構體的實際記憶體消耗是8個位元組,結構體的對齊是min( sizeof( long ), pack_value ) = 4位元組,所以整個結構占用的空間是8個位元組。

struct s2

;所以實際記憶體消耗是24自己,整體對齊方式是8位元組,所以整個結構占用的空間是24位元組。

#pragma pack()

所以:sizeof(s2) = 24, s2的c後面是空了3個位元組接著是d。

邊界對齊問題

結構體邊界對齊 許多實際的計算機系統對基本型別資料在記憶體中存放的位置有限制,它們會要求這些資料的首位址的值是某個數k 通常它為4或8 的倍數,這就是所謂的記憶體對齊,而這個k則被稱為該資料型別的對齊模數 alignment modulus 當一種型別s的對齊模數與另一種型別t的對齊模數的比值是大於...

整數邊界對齊方式 c中結構體邊界對齊

原則1 普通資料成員對齊規則 第乙個資料成員放在offset為0的地方,以後每個資料成員儲存的起始位置要從該成員大小的整數倍開始 比如int在32位機為 位元組,則要從4的整數倍位址開始儲存 原則2 結構體成員對齊規則 如果乙個結構裡有某些結構體成員,則該結構體成員要從其內部最大元素大小的整數倍位址...

結構體邊界對齊

許多實際的計算機系統對基本型別資料在記憶體中存放的位置有限制,它們會要求這些資料的首位址的值是某個數k 通常它為4或8 的倍數,這就是所謂的記憶體對齊,而這個k則被稱為該資料型別的對齊模數 alignment modulus 當一種型別s的對齊模數與另一種型別t的對齊模數的比值是大於1的整數,我們就...