1、平台原因(移植原因):不是所有的硬體平台都能訪問任意位址上的任意資料的;某些硬
件平台只能在某些位址處取某些特定型別的資料,否則丟擲硬體異常。
2、效能原因:資料結構(尤其是棧)應該盡可能地在自然邊界上對齊。原因在於,為了訪問
未對齊的記憶體,處理器需要作兩次記憶體訪問;而對齊的記憶體訪問僅需要一次訪問。
每個特定平台上的編譯器都有自己的預設「對齊係數」(也叫對齊模數)。程式設計師可以通過預編
譯命令#pragma pack(n),n=1,2,4,8,16來改變這一係數,其中的n就是你要指定的「對齊係數」。
資料成員對齊規則:結構(struct)(或聯合(union))的資料成員,第乙個資料成員放在offset
為0的地方,以後每個資料成員的對齊按照#pragma pack 指定的數值和這個資料成員自身長度中,比較小的那個進行。
結構(或聯合)的整體對齊規則:在資料成員完成各自對齊之後,結構(或聯合)本身也要進
行對齊,對齊將按照#pragma pack 指定的數值和結構(或聯合)最大資料成員長度中,比較小的那個進行。
結合1、2顆推斷:當#pragma pack 的n值等於或超過所有資料成員長度的時候,這個n
值的大小將不產生任何效果。
win32平台下的
微軟c編譯器(
cl.exe
for 80×86)的對齊策略:
1)
結構體變數
的首位址是其最長基本型別成員的整數倍
備註:編譯器在給結構體開闢空間時,首先找到結構體中最寬的基本
資料型別
,然後尋找
記憶體位址
能是該基本資料型別的整倍的位置,作為結構體的首位址。將這個最寬的基本資料型別的大小作為上面介紹的對齊模數。
2) 結構體每個成員相對於結構體首位址的
偏移量(offset)都是成員大小的整數倍,如有需要編譯器會在成員之間加上填充位元組(internal adding)
備註:為結構體的乙個成員開闢空間之前,編譯器首先檢查預開闢空間的首位址相對於結構體首位址的偏移是否是本成員的整數倍,若是,則存放本成員,反之,則在本成員和上乙個成員之間填充一定的位元組,以達到整數倍的要求,也就是將預開闢空間的首位址後移幾個位元組。
3) 結構體的總大小為結構體最寬基本型別成員大小的整數倍,如有需要,編譯器會在最末乙個成員之後加上填充位元組(trailing padding)
備註:結構體總大小是包括填充位元組,最後乙個成員滿足上面兩條以外,還必須滿足第三條,否則就必須在最後填充幾個位元組以達到本條要求。
我們通過一系列例子的詳細說明來證明這個規則吧!
我試驗用的編譯器包括gcc 3.4.2 和vc6.0的c編譯器,平台為windows xp + sp2。
我們將用典型的struct對齊來說明。首先我們定義乙個struct:
#pragma pack(n)
struct test_t
;#pragma pack(n)
首先我們首先確認在試驗平台上的各個型別的size,經驗證兩個編譯器的輸出均為:
sizeof(char) = 1
sizeof(short) = 2
sizeof(int) = 4
我們的試驗過程如下:通過#pragma pack(n)改變「對齊係數」,然後察看sizeof(struct test_t)的值。
輸出結果:sizeof(struct test_t) = 8 [兩個編譯器輸出一致]
分析過程:
#pragma pack(1)
struct test_t ;
#pragma pack()
成員總大小=8
整體對齊係數= min((max(int,short,char), 1) = 1
整體大小(size)=$(成員總大小)按$(整體對齊係數)圓整= 8 [注1]
輸出結果:sizeof(struct test_t) = 10 [兩個編譯器輸出一致]
分析過程:
#pragma pack(2)
struct test_t ;
#pragma pack()
成員總大小=9
整體對齊係數= min((max(int,short,char), 2) = 2
整體大小(size)=$(成員總大小)按$(整體對齊係數)圓整= 10
輸出結果:sizeof(struct test_t) = 12 [兩個編譯器輸出一致]
分析過程:
#pragma pack(4)
struct test_t ;
#pragma pack()
成員總大小=9
整體對齊係數= min((max(int,short,char), 4) = 4
整體大小(size)=$(成員總大小)按$(整體對齊係數)圓整= 12
輸出結果:sizeof(struct test_t) = 12 [兩個編譯器輸出一致]
分析過程:
#pragma pack(8)
struct test_t ;
#pragma pack()
成員總大小=9
整體對齊係數= min((max(int,short,char), 8) = 4
整體大小(size)=$(成員總大小)按$(整體對齊係數)圓整= 12
輸出結果:sizeof(struct test_t) = 12 [兩個編譯器輸出一致]
分析過程:
#pragma pack(16)
struct test_t ;
#pragma pack()
成員總大小=9
整體對齊係數= min((max(int,short,char), 16) = 4
整體大小(size)=$(成員總大小)按$(整體對齊係數)圓整= 12
8位元組和16位元組對齊試驗證明了「規則」的第3點:「當#pragma pack 的n值等於或超過所有資料成員長度的時候,這個n值的大小將不產生任何效果」。另外記憶體對齊是個很複雜的東西,上面所說的在有些時候也可能不正確。呵呵^_^
舉例說明:如上面的8位元組對齊中的「整體對齊」,整體大小=9按4圓整= 12
圓整的過程:從9開始每次加一,看是否能被4整除,這裡9,10,11均不能被4整除,到12時可以,則圓整結束。
int main()
記憶體對齊規則
隔了很久,搞忘了對齊的規則,現在重新複習了下,記下來謹防以後又忘記。1 可以根據 pragma pack 設定對齊係數,且叫為n 2 結構體中,對比每個成員變數自身的大小和n的大小。取小的個為標準,把這個小的叫a吧,稱為按a對齊 3 每個變變數的起始位址需要為a的整數倍,不是整數倍的則補齊。4 最後...
記憶體對齊 記憶體對齊規則解釋 記憶體對齊原理
一 記憶體對齊的原因 我們都知道計算機是以位元組 byte 為單位劃分的,理論上來說cpu是可以訪問任一編號的位元組資料的,我們又知道cpu的定址其實是通過位址匯流排來訪問記憶體的,cpu又分為32位和64位,在32位的cpu一次可以處理4個位元組 byte 的資料,那麼cpu實際定址的步長就是4個...
struct 記憶體對齊規則
1 確定資料成員的offset位址 a 基本資料型別 不包括陣列 struct class uinon 起始offset位址,規律如下,sizeof atom type n n 0,1,2,3.例子 char 0,1,2,3.int 0,4,8,12.double 0,8,16,24.b 組合資料成...