1. 程式人生 > >關於記憶體對齊#pragma pack( n )和__declspec( align(#) 的理解

關於記憶體對齊#pragma pack( n )和__declspec( align(#) 的理解

     有問題歡迎指正

     關於記憶體對齊,是程式設計師指定將記憶體中資料放在“對齊”的位置上,這雖然造成了部分的記憶體空間的浪費,但可以提高計算機的速度。

     這個“對齊”的位置,就是指可以被一個數整除的地址,這個數叫做“對齊引數”,一般是1,2,4,8,16……具體這個引數的選取就要用到#pragma pack( n )和__declspec( align(#) 中的n,#以及資料本身所佔位元組的大小,比如char=1,int=4(32位)……

編譯器的預設位元組對齊方式(自然對界)

在預設情況下,C編譯器為每一個變數或是資料單元按其自然對界條件分配空間。

在結構中,編譯器為結構的每個成員按其自然對界(alignment)條件分配空間。各個成員按照它們被宣告的順序在記憶體中順序儲存(成員之間可能有插入的空位元組),第一個成員的地址和整個結構的地址相同。

C編譯器預設的結構成員自然對界條件為“N位元組對齊”,N即該成員資料型別的長度。如int型成員的自然對界條件為4位元組對齊,而double型別的結構成員的自然對界條件為8位元組對齊。若該成員的起始偏移不位於該成員的“預設自然對界條件”上,則在前一個節面後面新增適當個數的空位元組。

C編譯器預設的結構整體的自然對界條件為:該結構所有成員中要求的最大自然對界條件。若結構體各成員長度之和不為“結構整體自然對界條件的整數倍,則在最後一個成員後填充空位元組。

放一句公式:

當一個變數或結構體同時受兩者影響時,__declspec( align(#) 的優先順序高。

     成員的地址決定於n及#,其要麼是n的倍數,要麼是#的倍數,要麼是成員的大小的倍數,取最小。

        結構體最後的大小於#有關,其要麼是#的倍數,要麼是結構體中最大對其引數的倍數,取最大。

C


#pragma pack( 4 )

__declspec( align(16)struct A 

{

   char a;資料成員對齊規則,第一個成員放在offset=0的位置,a放在[0]位元組

   short b; #=16>n=4>sizeof(short)=2,對齊引數選2,即b的地址必須可以被2整除,則[1]跳過,b放在[2,3]裡

   int c; #=16>n=4=sizeof(int)=4,對齊引數選4,c的首地址若不跳過為4,可以被4整除,則c放在[4,5,6,7]

};

則這個結構體最後的大小即sizeof(A)=8? 公式第二句,結構體A中最大對齊引數是int c的4,#=16>4,則取16的倍數,結構體最後的大小為16.

特殊:如果有結構體B中巢狀一個結構體A,如果A受__declspec( align(#) 影響過,由於優先順序高,則A的對齊引數為#,如果沒有影響過,A結構體中的最大對齊引數與n選最小值作為對其引數。

#pragma pack( 4 )

struct B

{

             char a;同樣,a放在[0]

             A b; 結構體A受__declspec( align(#) 影響,對齊引數為16,長度為16,則b放在[16,17…… 32]

             int c; c的對齊引數為4,放在[36,37,38,39]

};

現在的記憶體大小為40,能被4整除,所以sizeof(B)=40

如果不受__declspec( align(#) 影響

#pragma pack( 4 )

struct A

{

             char a; a放在[0]位元組

             short b; b放在[2,3]裡

             int c; c放在[4,5,6,7]

};

現在A的記憶體大小為8,可以被4整除,所以sizeof(A)=8,A的最大對齊引數是4

#pragma pack( 4 )

struct B

{

             char a;同樣,a放在[0]

             A b;比較A的最大對齊引數4和n=4的最小值,則b的對齊引數也是4,放在[4,5…… 11]

             int c;對齊引數為4,放在[12,13,14,15]

};

現在的記憶體大小為16,能被4整除,所以sizeof(B)=16