c 9 結構體對齊計算等

2021-10-08 13:31:30 字數 4359 閱讀 9055

我們看如下列子,並考慮結構體每個成員屬性偏移

struct mystruct

;

然後我們檢視記憶體結構:

我們驚訝的差異在name之後空出了3個位元組記憶體cc,而在genderheight記憶體結構中同樣也多出了3個位元組的cc.乙個多出了6個空白位元組,那麼加上固有的26位元組那麼這個結構體共占用32位元組。

造成這樣的現象是由於c存在結構體對齊機制引起的,在編譯引數由zp1,zp2,zp4,zp8,zp16控制。比如zp1為對齊大小為1,zp8為8位元組對齊。預設為zp8

上述的例子如果想輸出26只需要修改編譯引數為zp1即可。

結構體對齊作用(1):

控制的是每個成員屬性對於結構體初始位址的偏移

假設結構體對齊大小為n,結構體成員為y,結構體初始偏移為x,那麼偏移必須為x%min(n,sizeof(y))==0。(其中min函式表示取兩個數最小值)

以本例為例:

構造乙個mystruct物件名為person,我們強制假設person的位址是0.那麼我來計算這個結構體中的每個成員的偏移量。

struct mystruct

;void

main

(int argc,

char

*ar**,

char

*envp)

我們用假設對齊大小為8。

我們看第乙個結構體成員char name[9];。由於在結構體第一位所以偏移位址為0,由於0%min(8,9)==0所以name偏移為0。

我們看第二個結構體成員age。由於第乙個結構體成員name大小為9,所以age偏移量為9,我們取模運算9%min(8,4)==1,不符合對齊大小,所增大12可以滿足12%min(8,4)==0,故偏移為12.

後面成員模擬不做講解。

當然我們可以使用系統的api來幫助我們迅速計算成員偏移.

struct mystruct

;void main(int argc,char *ar**,char *envp)

offsetof實現是乙個巨集函式,思想比較簡單,構造乙個執行0位址的mystruct,對成員取位址即可

#ifdef __cplusplus

#define offsetof(s,m) ((size_t)&reinterpret_cast((((s*)0)->m)))

#else

#define offsetof(s,m) ((size_t)&(((s*)0)->m))

struct newmystruct

;void

main

(int argc,

char

*ar**,

char

*envp)

根據上乙個章節講解的每個成員的偏移計算,height偏移為24那麼這個結構體大小應該是24+4=28(由於float大小為4,所最後乙個成員的偏移加上大小理所當然為結構體大小)

然而結果輸出:32

結構體對齊作用(2):

結構體對齊控制整個結構體的大小。

結構體的大小公式:

設結構體每個成員為 m1,m2,m3…

對齊大小為n

結構體大小為y

temp=min(n,max(sizof(m1),sizeof(m2),sizeof(m3),....))y%temp==0

帶入本例

struct newmystruct

;

temp = min(8,max(5,4,1,8,4)) = 8此時我們知道這個結構體至少大小為28,而28%8==4,不滿足y%temp==0,所以size擴大為32。

除了使用zp1,zp2,zp4,zp8,zp16控制全域性程式結構體大小。還可以使用編譯巨集指令單獨對某個某個結構體,或對後續全部的結構體對齊指定。

1)#pragma pack( [ n] )

2)#pragma pack( [ [ , ] [ identifier, ] ] [ n ] )

#pragma pack( [ n] ) 用法

這個編譯巨集後面所有的全部對齊為指定數量

//後續所有結構對其為1

//對齊為1

#pragma pack(1)

struct mystruct

;//對齊為1

struct mystruct2

;#pragma pack(4)

//對齊為4

struct mystruct3

;

如果你想控制範圍請用如下語法:

//儲存當前結構體巨集對齊大小

#pragma pack(push)

#pragma pack(1)

//對齊為1

struct mystruct

;//彈出儲存的結構體的巨集對齊大小

#pragma pack(pop)

//對齊為預設

struct mystruct2

;

第乙個引數 push pop 用於 儲存或者彈出巨集大小。

第二個引數 設定乙個名詞

第三個引數 對齊大小

//儲存當前對其大小,並設定對齊大小為1

#pragma pack(push,myaligment,1)

//對齊為1

struct mystruct

;//還原儲存的對其大小

#pragma pack(pop,myaligment)

//對齊為預設

struct mystruct2

;

這個編譯指令主要用於巢狀用途。

//儲存當前對其大小,並設定對齊大小為1

#pragma pack(push,myaligment,1)

//對齊為1

struct mystruct

;//儲存當前對其大小,並設定對齊大小為4

#pragma pack(push,myaligment2,4)

//對齊為4

struct mystruct2

;//還原儲存的對其大小由於myaligment2巢狀在myaligment,

//所以會直接拋棄myaligment2和myaligment

#pragma pack(pop,myaligment)

//對齊為預設

struct mystruct3

;

//儲存當前對其大小,並設定對齊大小為1

#pragma pack(push,myaligment,1)

//對齊為1

struct mystruct

;//儲存當前對其大小,並設定對齊大小為4

#pragma pack(push,myaligment2,4)

//對齊為4

struct mystruct2

;//只拋棄對齊4,但是myaligment還在

#pragma pack(pop,myaligment2)

//對齊為1

struct mystruct3

;

結構體對齊計算方式

結構體的大小也不是成員型別大小的簡單相加。需要考慮到系統在儲存結構體變數時的位址對齊問題。由於儲存變數位址對齊的問題,結構體大小計算必須滿足兩條原則 一 結構體成員的偏移量必須是成員大小的整數倍 0被認為是任何數的整數倍 二 結構體大小必須是所有成員大小的整數倍 陣列除外,結構體中的結構體按單個變數...

c 結構體對齊

1 當前偏移量 當前填充數 當前變數大小 0 2 總偏移大小 末尾填充數 最寬變數大小 0 必須先滿足1 再滿足2。例如 如下 struct a 由上可知 總偏移量 4 1 1 2 末尾補數0 最寬變數大小4 0。所以sizeof a 8。即4 1 1 2 8 快速記憶 4 1 1 2 8 stru...

C語言 結構體struct 結構體對齊

1 定義乙個結構體 順便例項結構體變數 struct tag 結構體型別名 struct tag 這兩者共同構成了結構體型別 單獨的tag 結構體型別名 不能稱之為結構體型別 結構體變數名 2 定義的同時使用typedef 相當於定義結構體 為結構體起新名字 typedef struct tag 結...