記憶體對齊 結構體對齊

2021-06-18 03:53:39 字數 3569 閱讀 9805

現在已知32位機器上各種資料型別的長度如下:

char:1(有符號無符號同)    

short:2(有符號無符號同)    

int:4(有符號無符號同)    

long:4(有符號無符號同)    

float:4    double:8

重要規則:

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

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

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

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

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

對齊的演算法: 

由於各個平台和編譯器的不同,現以本人使用的gcc version 3.2.2編譯器(32位x86平台)為例子,來討論編譯器對struct資料結構中的各成員如何進行對齊的。   

相同的對齊方式下,結構體內部資料定義的順序不同,結構體整體佔據記憶體空間也不同,如下: 

設結構體如下定義: 

struct a 

; 結構體a中包含了4位元組長度的int乙個,1位元組長度的char乙個和2位元組長度的short型資料乙個。所以a用到的空間應該是7位元組。但是因為編譯器要對資料成員在空間上進行對齊。所以使用sizeof(strcut a)值為8。 

現在把該結構體調整成員變數的順序。 

struct b 

; 這時候同樣是總共7個位元組的變數,但是sizeof(struct b)的值卻是12。 

下面我們使用預編譯指令#progma pack (value)來告訴編譯器,使用我們指定的對齊值來取代預設的。 

#progma pack (2) /*指定按2位元組對齊,等價於#pragma pack(push,2)*/

struct c 

; #progma pack ()

/*取消指定對齊,恢復預設對齊,等價於#pragma pack(pop)*/

sizeof(struct c)值是8。 

修改對齊值為1: 

#progma pack (1) /*指定按1位元組對齊*/

struct d 

; #progma pack () /*取消指定對齊,恢復預設對齊*/

sizeof(struct d)值為7。 

對於char型資料,其自身對齊值為1,對於short型為2,對於int,float,double型別,其自身對齊值為4,單位位元組。

這裡面有四個概念值: 

1.資料型別自身的對齊值:就是上面交代的基本資料型別的自身對齊值。 

2.指定對齊值:#progma pack (value)時的指定對齊值value。 

3.結構體或者類的自身對齊值:其資料成員中自身對齊值最大的那個值。 

4.資料成員、結構體和類的有效對齊值:自身對齊值和指定對齊值中小的那個值。 

有了這些值,我們就可以很方便的來討論具體資料結構的成員和其自身的對齊方式。有效對齊值n是最終用來決定資料存放位址方式的值,最重要。有效對齊n,就是表示「對齊在n上」,也就是說該資料的"存放起始位址%n=0". 而資料結構中的資料變數都是按定義的先後順序來排放的。第乙個資料變數的起始位址就是資料結構的起始位址。結構體的成員變數要對齊排放,結構體本身也要根 據自身的有效對齊值圓整(就是結構體成員變數占用總長度需要是對結構體有效對齊值的整數倍,結合下面例子理解)。這樣就不能理解上面的幾個例子的值了。 

例子分析: 

分析例子b; 

struct b 

; 假設b從位址空間0x0000開始排放。該例子中沒有定義指定對齊值,在筆者環境下,該值預設為4

第乙個成員變數b的自身對齊值是1,比指定或者預設指定對齊值4小,所以其有效對齊值為1,所以其存放位址0x0000符合0x0000%1=0.

第二個成員變數a,其自身對齊值為4,所以有效對齊值也為4,所以只能存放在起始位址為0x00040x0007這四個連續的位元組空間中,符合0x0004%4=0, 且緊靠第乙個變數。

第三個變數c,自身對齊值為2,所以有效對齊值也是2,可以存放在0x00080x0009這兩個位元組空間中,符合0x0008%2=0。所以從0x0000到0x0009存放的都是b內容。

再看資料結構b的自身對齊值為其變數中最大對齊值(這裡是b)所以就是4,所以結構體的有效對齊值也是4。根據結構體圓整的要求,0x0009到0x0000=10位元組,(10+2)%4=0。所以0x0000a0x000b也為結構體b所占用。故b從0x0000到0x000b共有12個位元組,sizeof(struct b)=12

同理,分析上面例子c: 

#progma pack (2) /*指定按2位元組對齊*/

struct c 

; #progma pack () /*取消指定對齊,恢復預設對齊*/ 

第乙個變數b的自身對齊值為1,指定對齊值為2,所以,其有效對齊值為1,假設c從0x0000開始,那麼b存放在0x0000,符合0x0000%1=0;

第二個變數,自身對齊值為4,指定對齊值為2,所以有效對齊值為2,所以順序存放在0x0002、0x0003、0x0004、0x0005四個連續位元組中,符合0x0002%2=0。

第三個變數c的自身對齊值為2,所以有效對齊值為2,順序存放在0x0006、0x0007中,符合0x0006%2=0。所以從0x0000到0x00007共八字節存放的是c的變數。

又c的自身對齊值為4,所以c的有效對齊值為2。又8%2=0,c只占用0x0000到0x0007的八個位元組。所以sizeof(struct c)=8.

結構體對齊(記憶體對齊

有的時候,在腦海中停頓了很久的 顯而易見 的東西,其實根本上就是錯誤的。就拿下面的問題來看 structt 使用sizeof t 將得到什麼樣的答案呢?要是以前,想都不用想,在32位機中,int是4個位元組,char是1個位元組,所以t一共是5個位元組。實踐出真知,在vc6中測試了下,答案確實8個位...

結構體的記憶體對齊

原則一 結構體中元素是按照定義順序乙個乙個放到記憶體中去的,但並不是緊密排列的。從結構體儲存的首位址開始,每乙個元素放置到記憶體中時,它都會認為記憶體是以它自己的大小來劃分的,因此元素放置的位置一定會在自己寬度的整數倍上開始 以結構體變數首位址為0計算 原則二 在經過第一原則分析後,檢查計算出的儲存...

結構體儲存記憶體對齊

解析c語言結構體對齊 記憶體對齊問題 結構體對齊原因有很大部分是因為計算機掃瞄的記憶體單元個數,也就是資料匯流排的大小。原則1 資料成員對齊規則 結構 struct或聯合union 的資料成員,第乙個資料成員放在offset為0的地方,以後每個資料成員儲存的起始位置要從該成員大小的整數倍開始 比如i...