結構體和聯合體相關知識總結

2021-07-24 17:07:15 字數 4730 閱讀 1800

1.結構體和陣列都是聚合資料型別,它們之間有以下的區別:

陣列是同種型別元素的集合,而結構體是相同或者不同的資料元素的集合。

陣列名在傳參時會退化為乙個指標,但是結構體在作為函式引數時不會發生退化。

陣列可以通過下標來訪問某個元素,而結構體是通過結構體的成員名來訪問成員的。

struct a

;

這叫做宣告了乙個結構體型別,並沒有開闢空間。

上面定義的結構體是定義了一種聚合型別,這是一種自定義型別。

而int . float . char.等屬於內建型別。

結構體的基本概念:

一般情況下,結構體標籤和結構體變數名必須至少有乙個。

在定義乙個結構體變數時,可以使用標籤,例如struct tag a;這裡的a即就是結構體變數。定義結構體變數時開闢空間。

訪問結構體成員時可以有兩種方法:

1.直接訪問:使用(.)操作符,.操作符的優先順序是從左到右。

2.間接訪問:使用箭頭操作符(->),應注意,這裡的箭頭操作符的左運算元必須是指標變數。

結構體的不完整宣告:

如果有兩個結構體需要互相引用對方,那麼最好使用不完整宣告,在引用對方時最好定義指向那個結構體的指標,而不是定義那個結構體的變數。

結構體的初始化類似與指標,可以使用{}來初始化結構體成員。

在c語言中,結構體成員至少要有乙個,在vs2013下,不能定義乙個空結構體,而在linux下,空結構體大小為0,在c++下,空結構體的大小為1.

結構體為什麼會有記憶體對齊?

對齊原因:

1、平台原因(移植原因):

不是所有的硬體平台都能訪問任意位址上的任意資料的;

某些硬體平台只能在某些位址處取某些特定型別的資料,否則丟擲硬體異常。

2、效能原因:資料結構(尤其是棧)應該盡可能地在自然邊界上對齊。

原因在於,為了訪問未對齊的記憶體,處理器需要作兩次記憶體訪問;而對齊的記憶體訪問僅需要一次訪問。

其他:

指定對齊值:#pragma pack (value)時的指定對齊值value。

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

結構體的記憶體對齊原則:

1.第乙個成員在與結構體變數偏移量為0的位址處——也就是第乙個變數沒有對齊數

2.其他成員變數要對齊到它的(對齊數)的整數倍的位址處

//對齊數 = 編譯器預設的乙個對齊數與該成員大小的較小值。

// vs—-預設為8;

// linux—預設為4

3.結構體總大小為最大對齊數(每個成員變數除了第乙個成員都有乙個對齊數)的整數倍。

4.如果巢狀了結構體的情況,巢狀的結構體對齊到自己的最大對齊數的整數倍處,結構體的整體大小就是

最大對齊數(含巢狀結構體的對齊數)的整數倍。

下面通過例子來分析:(在linux下預設的對齊數是4)

所以結構體p的大小為 4(e)+4(x)+1(y)+3(補得空間,因為ss結構體的最大對齊數為4) = 12(4的倍數)

12+3*20(3個結構體的大小) = 72

72(是3的倍數)+3 = 75

75(不是4的倍數,所以加1) +1 = 76(是4的倍數)

76+4(指標變數p的大小) = 80(是結構體p的最大對齊數 4的倍數)

所以結構體p的大小為80

位段(一般在協議中使用):(可以訪問乙個資料中的bit位)

使用位域的主要目的是壓縮儲存

位段成員必須宣告為int 或unsigned int 或signed int型別。

宣告乙個位段時:在成員名後是乙個冒號和整數。例如:unsigned int a: 2.

其大致的規則為:

1) 如果相鄰位域字段的型別相同,且其位寬之和小於型別的sizeof大小,則後面的字段將緊鄰前乙個字段儲存,直到不能容納為止;

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

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

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

5)結構體總大小為最大對齊數的整數倍。

總體來看,位段的對齊方式和結構體對齊方式類似,宣告位域時最好宣告為同一種型別的。

測試位段在記憶體中的儲存方式:

位段的對齊方式類似與結構體:

注意:

當乙個位段變數的大小可以和前面已定義的位段存放在乙個整型大小的空間時,就不用另外開闢空間,但是如果不夠儲存,則另外再開闢乙個整型變數的大小,從它的型別的對齊數的倍數的位址處開始儲存。

聯合體(union):(也有記憶體對齊,所有的成員都必須對齊)當多個資料需要共享記憶體或者多個資料每次只取其一時,可以利用聯合體(union)。

1)聯合體是乙個結構;

2)它的所有成員相對於基位址的偏移量都為0;

3)此結構空間要大到足夠容納最」寬」的成員;

4)其對齊方式要適合其中所有的成員;

下面解釋這四條描述:

由於聯合體中的所有成員是共享一段記憶體的,因此每個成員的首位址相對於於聯合體變數的基位址的偏移量為0,即所有成員的首位址都是一樣的。為了使得所有成員能夠共享一段記憶體,因此該空間必須足夠容納這些成員中最寬的成員。對於這句「對齊方式要適合其中所有的成員」是指其必須符合所有成員的自身對齊方式。

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

struct aobj;//8

struct ;//20

double x;//8

};//最終結構體的大小為40個位元組

int main()

應特別注意的是:聯合體也需要記憶體對齊,指的是它內部所有的成員都應該自身對齊。

2017.1.17.更新

求解結構體中任意乙個變數的位址的偏移量?——–offsetof巨集

1.#define offsetof(type,member) (size_t)&(((type*)0)->member)
巨集的功能:返回結構體中成員變數的偏移量

分析表示式:由內到外逐層分析

①0

②(type )0—–可以看出,此表示式的意義是:將整型0強制型別轉換為(type )型別的,(這裡的type指的是結構體型別),

那麼分析得:將0強轉為了結構體指標型別,那麼0代表的就是乙個sizeof(type)大小的記憶體空間的首位址

③(type *)0->member—-可以這樣理解:定義了乙個結構體指標,即強制型別轉換後的0,然後是訪問結構體成員的兩種方法中的第二種,使用指標,形式為:結構體指標->成員變數,所以這個表示式就是訪問結構體變數。

④&(((type*)0)->member)——這個很好理解,就是給成員變數取位址。

⑤(size_t)&(((type*)0)->member)——-將成員變數的位址強制型別轉換為size_t(unsigned int),位址肯定不會為負啦…

下面舉例來看:

結構體和聯合體

結構體是一些值的集合,這些值成為它的成員。這和陣列有些類似。結構體和陣列最大的不同是,陣列的元素都是相同型別的,而結構體裡的成員可以具有不同的型別。陣列元素可以通過下標來訪問,而結構體成員長度可能不同,所以不能通過下標訪問。每個結構體成員都有自己的名字,所以結構體成員是通過名字訪問的。結構體變數屬於...

聯合體和結構體

一 前言 聯合體 union 與 結構體 struct 有一些相似之處。但兩者有本質上的不同。在結構體中,各成員有各自的記憶體空間,乙個結構變數的總長度是各成員長度之和 而在 聯合 中,各成員共享一段記憶體空間,乙個聯合變數的長度等於各成員中最長的長度 應該說明的是,這裡所謂的共享不是指把多個成員同...

結構體聯合體

在c中,結構也是一種資料型別,可以使用結構變數,因此,象其它型別的變數一樣,在使用結構變數時要先對其定義。定義結構變數的一般格式為 struct 結構名 結構變數 結構名是結構的識別符號不是變數名。型別為第二節中所講述的五種資料型別 整型 浮點型 字元型 指標型和無值型 構成結構的每乙個型別變數稱為...