記憶體對齊問題(結構體,聯合體,位段)

2021-08-14 22:23:53 字數 3486 閱讀 2358

結構體

typedef

struct a

a;typedef

struct b

b;typedef

struct c

c;

對於結構體a,b,c.它們具有同樣的結構體成員,只是調換了先後順序,我們來觀察它們的大小是否相同?

結果顯示在sizeof計算結構體大小時,經常得到的值比結構體成員所佔記憶體總和要大,這是因為成員在儲存時有對齊的規則。

結構體對齊的規則

1、資料成員對齊規則:結構(struct)(或聯合(union))的資料成員,第乙個資料成員放在offset為0的地方,以後每個資料成員的對齊按照#pragma pack指定的數值和這個資料成員自身長度中,比較小的那個進行。

2、結構(或聯合)的整體對齊規則:在資料成員完成各自對齊之後,結構(或聯合)本身也要進行對齊,對齊將按照#pragma pack指定的數值和結構(或聯合)最大資料成員長度中,比較小的那個進行。

3、結合1、2可推斷:當#pragma pack的n值等於或超過所有資料成員長度的時候,這個n值的大小將不產生任何效果。

先來剖析一下上述結構體的內部儲存結構:

以a為例進行分析:首先將結構體的第乙個資料成員c1放在0偏移處;下來判斷1偏移處是不是第二個成員c2的對齊數(1)的整數倍,是,直接填充

(占用乙個位元組);最後判斷2偏移處是不是第三個成員i的對齊數(4)的整倍數,不是,向後偏移2個位元組(2-3,浪費兩個位元組),偏移到第三個成員的對齊數(4)的1倍處,將int型資料填充,向後偏移4個位元組。

根據上例我們也不難得出結論:根據邊界對齊要求一般降序排列結構成員可以最大限度地減少結構儲存中浪費的記憶體空間。

為什麼存在記憶體對齊?

一般來說,該用多大的空間就開闢多大的記憶體就好了,像strcuta來說,兩個char型別和乙個int型別的變數,大小加起來不應該是6位元組大小,為什麼結果會是8?那多出的兩個位元組不是被浪費了嗎?這裡便是為了求得記憶體對齊中以空間換時間的效果,為了訪問未對齊的記憶體,處理器需做兩次訪問,若遵循記憶體對齊原則只需訪問依次。

結構體內存對齊特殊情況分析

(1)結構體中不存在變數

typedef

struct d

d;int main()

vs2013下執行可以通過:

系統認為雖然結構體中沒有任何變數,但只要建立結構體就分配乙個位元組,以建立存在感(月銷售業績為0的售樓小姐起碼也有底薪,雖然很少,但有的公司也會很苛刻,沒有業績的話底薪也甭想拿)正常情況下結構體至少要存在乙個成員。

vs2008下執行不能通過:

(2)結構體中巢狀結構體

typedef

struct e

e;typedef

struct f

f;int main()

測試結果是24

(3)結構體中存在柔性陣列

結構體中最後乙個元素允許是未知大小的陣列。

typedef

struct g

g;int main()

測試發現結構體g的大小為4,說明系統沒有為陣列a[0]分配空間,既然系統不給,那我們自己手動分配

我們明明為它分配了10個整形大小空間為什麼結果仍然是4呢?這就要從柔性陣列的特性說起:定義結構體的時候我們知道柔性陣列只是乙個允許是未知大小的陣列,它是用來擴充套件結構體大小的,它自己和結構體並沒有什麼關係,只是我們在使用時把它當做結構體的乙個成員,通俗說,柔性陣列其實並不佔結構體的記憶體大小。

聯合體

聯合的宣告和結構類似,但它的行為方式卻和結構不同,聯合的所有成員引用的是記憶體中的相同位置。union聯合體大小取決於所有成員中,占用空間最大的乙個成員的大小。

union a

a;union b

b;union c

c;int main()

在a中最大的成員是double型變數所以聯合體a大小為8;在b中int型別為最大,所以b的大小為4的整數倍,聯合體b占用空間為12(最接近9的對界);在c中變數均為char型別,所以聯合體c的大小為9.

位段

位段的宣告和結構體類似,但它的成員是乙個或多個位的字段,這些不同長度的字段實際上儲存於乙個或多個整形變數中。

位段(struct)的記憶體對齊規則:

1.如果相鄰位域字段的型別相同,且其位寬之和小於sizeof(type)的大小,則後面的字段緊鄰前乙個位元組儲存,直到 容納不下為止;基本成員是連續儲存的,若這個單元空間放不下下乙個成員,則新開闢乙個單元空間,這樣可以節 省記憶體空間。

2.如果相鄰位域字段的型別相同,但其位寬之和大於sizeof(type)的大小,則後面的字段將從新的單元開始,偏移量 為其型別大小的整數倍。

3.如果相鄰位域字段的型別不相同,則各編譯器的實現有差異,vc6採取不壓縮方式,dev-c++採取壓縮。

4.如果位域字段之間穿插著非位域字段,則不進行壓縮。

5.結構體的總大小為最大對齊數的整數倍。因為位斷成員必須宣告為int、signed int或unsigned int型別,因此結構體的 大小都是4的整數倍。

總結

#pragma pack(4)//預設對齊數為4

struct a

a; //結構體a總大小:16

union b

b; //聯合體b總大小:16

struct c

c; //位段c總大小:16

struct d

; //總和結構體d大小:60

聯合體,位域, 結構體對齊

聯合體union 當多個資料需要共享記憶體或者多個資料每次只取其一時,可以利用聯合體 union 在c programming language 一書中對於聯合體是這麼描述的 1 聯合體是乙個結構 2 它的所有成員相對於基位址的偏移量都為0 3 此結構空間要大到足夠容納最 寬 的成員 1下面解釋這四...

結構體位段 列舉 聯合體(共用體)

位段,c語言允許在乙個結構體中以位為單位來指定其成員所佔記憶體長度,這種以位為單位的成員稱為 位段 或稱 位域 bit field 利用位段能夠用較少的位數儲存資料。位段的宣告和結構是類似的,有兩個不同 位段的成員必須是 int unsigned int signed int char 整形家族。位...

聯合體 位域結構體 聯合體的妙用

在c語言中,變數的定義是分配儲存空間的過程。一般的,每個變數都具有其獨有的儲存空間,那麼可不可以在同乙個記憶體空間中儲存不同的資料型別 不是同事儲存 呢?答案是可以的,使用聯合體就可以達到這樣的目的。聯合體也叫共用體,在c語言中定義聯合體的關鍵字是union。定義乙個聯合型別的一般形式為 union...