結構體在記憶體中的對齊規則

2021-07-14 03:50:25 字數 3866 閱讀 6885

結構體在記憶體中的對齊規則

標籤:儲存

struct

測試iostream

c2011-11-15 19:32 4717人閱讀

(9) 收藏

舉報乙個結構體變數定義完之後,其在記憶體中的儲存並不等於其所包含元素的寬度之和。

例一:#include

using namespace std;

struct x

char a;

int b;

double c;

}s1;

void main()

cout << sizeof(s1) << endl;

cout << sizeof(s1.a) << endl;

cout << sizeof(s1.b) << endl;

cout << sizeof(s1.c) << endl;

比如例一中的結構體變數

s1定義之後,經測試,會發現

sizeof(s1

)= 16

,其值不等於

sizeof(s1.a) = 1

、sizeof(s1.b) = 4

和 sizeof(s1.c) = 8

三者之和,這裡面就存在儲存對齊問題。

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

0計算)。

比如此例,首先系統會將字元型變數

a存入第

0個位元組(相對位址,指記憶體開闢的首位址);然後在存放整形變數

b時,會以

4個位元組為單位進行儲存,由於第乙個四位元組模組已有資料,因此它會存入第二個四位元組模組,也就是存入到

4~8位元組;同理,存放雙精度實型變數

c時,由於其寬度為

8,其存放時會以

8個位元組為單位儲存,也就是會找到第乙個空的且是

8的整數倍的位置開始儲存,此例中,此例中,由於頭乙個

8位元組模組已被占用,所以將

c存入第二個

8位元組模組。整體儲存示意圖如圖

1所示。

考慮另外乙個例項。

例二:struct x

char a;

double b;

int c;

}s2;

在例二中僅僅是將

double

型的變數和

int型的變數互換了位置。測試程式不變,測試結果卻截然不同,

sizeof(s2)=24

,不同於我們按照原則一計算出的

8+8+4=20

,這就引出了我們的第二原則。

原則二:在經過第一原則分析後,檢查計算出的儲存單元是否為所有元素中最寬的元素的長度的整數倍,是,則結束;若不是,則補齊為它的整數倍。

例二中,我們分析完後的儲存長度為

20位元組,不是最寬元素長度

8的整數倍,因此將它補齊到

8的整數倍,也就是

24。這樣就沒問題了。其儲存示意圖如圖

2所示。

掌握了這兩個原則,就能夠分析所有資料儲存對齊問題了。再來看幾個例子,應用以上兩個原則來判斷。

例三:struct x

double a;

char b;

int c;     

}s3;

首先根據原則一來分析。按照定義的順序,先儲存

double型的a

,儲存在第

0~7個位元組;其次是

char型的b

,儲存在第

8個位元組;接下來是

int型的

c,順序檢查後發現前面三個四位元組模組都被占用,因此儲存在第

4個四位元組模組,也就是第

12~15

位元組。按照第一原則分析得到

16個位元組,

16正好是最寬元素

a的寬度

8的整數倍,因此結構體變數

s3所佔儲存空間就是

16個位元組。儲存結構如圖

3所示。

例四:struct x

double a;

char b;

int c;

char d;   

}s4;

仍然首先按照第一原則分析,得到的位元組數為

8+4+4+1=17

;再按照第二原則補齊,則結構體變數

s4所佔儲存空間為

24。儲存結構如圖

4所示:

例五:struct x

double a;

char b;

int c;

char d;

int e; 

}s5;

同樣結合原則一和原則二分析,可知在

s4的基礎上在結構體內部變數定義最後加入乙個

int型變數後,結構體所佔空間並未增加,仍為

24。儲存結構示意圖如圖

5所示。

例六:如果將例五中加入的變數

e放到第乙個定義的位置,則情況就不同了。結構體所佔儲存空間會變為

32。其儲存結構示意圖如圖

6所示。

struct x

int e;

double a;

char b;

int c;

char d;

}s6;

補充:前面所介紹的都是元素為基本資料型別的結構體,那麼含有指標、陣列或是其它結構體變數或聯合體變數時該如何呢?

1.包含指標型別的情況。只要記住指標本身所佔的儲存空間是

4個位元組就行了,而不必看它是指向什麼型別的指標。

例七:struct x              struct y               struct z

char *a;              int *b;                 double *c;

經測試,可知

sizeof(x)

、sizeof(y)

和sizeof(z)

的值都為4。

2.含有構造資料型別(陣列、結構體和聯合體)的情況。首先要明確的是計算儲存空間時要把構造體看作乙個整體來為其開闢儲存空間;其次要明確的是在最後補齊時是按照所有元素中的基本資料型別元素的最長寬度來補齊的,也就是說雖然要把構造體看作整體,但在補齊的時候並不會按照所含結構體所佔儲存空間的長度來補齊的(即使它可能是最長的)。

例八:struct x

char a;

int b;

double c;

struct y

char a;

x b;

經測試,可知

sizeof(x)為16

,sizeof(y)為24

。即計算

y的儲存長度時,在存放第二個元素

b時的初始位置是在

double

型的長度

8的整數倍處,而非

16的整數倍處,即系統為

b所分配的儲存空間是第

8~23

個位元組。

如果將y的兩個元素

char型的a

和x型的b

調換定義順序,則系統為

b分配的儲存位置是第

0~15

個位元組,為

a分配的是第

16個位元組,加起來一共

17個位元組,不是最長基本型別

double

所佔寬度

8的整數倍,因此要補齊到

8的整數倍,即

24。測試後可得

sizeof(y)

的值為24。

由於結構體所佔空間與其內部元素的型別有關,而且與不同型別元素的排列有關,因此在定義結構體時,在元素型別及數量確定之後,我們還應該注意一下其內部元素的定義順序。

結構體在記憶體中對齊

剛剛完成乙個檔案的遷移程式,其中遇到了結構體對齊的問題,所以拿出來說說,與各位博友們分享。我的程式很簡單,就是把之前通過乙個結構體 fwrite 到檔案 a 裡的內容讀出,然後轉給另乙個結構體儲存。程式是簡單,但我擔心的是之前把結構體 fwrite 到檔案 a 的程式對齊結構體規則是怎樣的?一定要知...

結構體的記憶體對齊規則

前言 結構體是一種自定義型別,其中包含了許多不同型別的變數,我們稱這些值為成員變數,那麼這種自定義型別的大小該怎麼計算呢?這才是我們今天討論的重點問題。要想計算結構體的大小,首先得了解結構體的記憶體對齊規則。對齊數 編譯器預設的對齊數 vs為8 linux為4 與 該成員大小的較小值 下面我們看兩個...

結構體在記憶體中的對其規則

乙個結構體變數定義完之後,其在記憶體中的儲存並不等於其所包含元素的寬度之和。例一 include using namespace std struct x s1 voidmain 比如例一中的結構體變數s1定義之後,經測試,會發現sizeof s1 16,其值不等於sizeof s1.a 1 siz...