sizeof進行結構體大小的判斷

2021-05-21 12:27:13 字數 3202 閱讀 4591

typedef struct

a_t;

typedef struct

b_t;

typedef struct

c_t;

void main()

void foo4(char a4) 

也許當你試圖回答c4的值時已經意識到c3答錯了,是的,c3!=3。這裡函式引數a3已不再是

陣列型別,而是蛻變成指標,相當於char* a3,為什麼?仔細想想就不難明白,我們呼叫

函式foo1時,程式會在棧上分配乙個大小為3的陣列嗎?不會!陣列是「傳址」的,呼叫者

只需將實參的位址傳遞過去,所以a3自然為指標型別(char*),c3的值也就為4。。但在確定復合型別成員的偏移位置時則是將復合型別

作為整體看待。 

這裡敘述起來有點拗口,思考起來也有點撓頭,還是讓我們看看例子吧(具體數值仍以vc

6為例,以後不再說明): 

struct s3 

; s1的最寬簡單成員的型別為int,s3在考慮最寬簡單型別成員時是將s1「打散」看的,所以

s3的最寬簡單型別為int,這樣,通過s3定義的變數,其儲存空間首位址需要被4整除,整

個sizeof(s3)的值也應該被4整除。 

c1的偏移量為0,s的偏移量呢?這時s是乙個整體,它作為結構體變數也滿足前面三個準則

,所以其大小為8,偏移量為4,c1與s之間便需要3個填充位元組,而c2與s之間就不需要了,

所以c2的偏移量為12,算上c2的大小為13,13是不能被4整除的,這樣末尾還得補上3個填

充位元組。最後得到sizeof(s3)的值為16。 

通過上面的敘述,我們可以得到乙個公式: 

結構體的大小等於最後乙個成員的偏移量加上其大小再加上末尾的填充位元組數目,即: 

sizeof( struct ) = offsetof( last item ) + sizeof( last item ) + sizeof( trail

ing padding ) 

到這裡,朋友們應該對結構體的sizeof有了乙個全新的認識,但不要高興得太早,有乙個

影響sizeof的重要參量還未被提及,那便是編譯器的pack指令。它是用來調整結構體對齊

方式的,不同編譯器名稱和用法略有不同,vc6中通過#pragma pack實現,也可以直接修改

/zp編譯開關。#pragma pack的基本用法為:#pragma pack( n ),n為位元組對齊數,其取值

為1、2、4、8、16,預設是8,如果這個值比結構體成員的sizeof值小,那麼該成員的偏移

量應該以此值為準,即是說,結構體成員的偏移量應該取二者的最小值,公式如下: 

offsetof( item ) = min( n, sizeof( item ) ) 

再看示例: 

#pragma pack(push) // 將當前pack設定壓棧儲存 

#pragma pack(2)// 必須在結構體定義之前使用 

struct s1 

; struct s3 

; #pragma pack(pop) // 恢復先前的pack設定 

計算sizeof(s1)時,min(2, sizeof(i))的值為2,所以i的偏移量為2,加上sizeof(i)等於

6,能夠被2整除,所以整個s1的大小為6。 

同樣,對於sizeof(s3),s的偏移量為2,c2的偏移量為8,加上sizeof(c2)等於9,不能被

2整除,新增乙個填充位元組,所以sizeof(s3)等於10。 

現在,朋友們可以輕鬆的出一口氣了, 

還有一點要注意,「空結構體」(不含資料成員)的大小不為0,而是1。試想乙個「不佔

空間」的變數如何被取位址、兩個不同的「空結構體」變數又如何得以區分呢?於是,「

空結構體」變數也得被儲存,這樣編譯器也就只能為其分配乙個位元組的空間用於佔位了。

如下: 

struct s5 ; 

sizeof( s5 ); // 結果為1 

8. 含位域結構體的sizeof

前面已經說過,位域成員不能單獨被取sizeof值,我們這裡要討論的是含有位域的結構體

的sizeof,只是考慮到其特殊性而將其專門列了出來。 

c99規定int、unsigned int和bool可以作為位域型別,但編譯器幾乎都對此作了擴充套件,允

許其它型別型別的存在。 

使用位域的主要目的是壓縮儲存,其大致規則為: 

1) 如果相鄰位域字段的型別相同,且其位寬之和小於型別的sizeof大小,則後面的字段將

緊鄰前乙個字段儲存,直到不能容納為止; 

2) 如果相鄰位域字段的型別相同,但其位寬之和大於型別的sizeof大小,則後面的字段將

從新的儲存單元開始,其偏移量為其型別大小的整數倍; 

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

,dev-c++採取壓縮方式; 

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

5) 整個結構體的總大小為最寬基本型別成員大小的整數倍。 

還是讓我們來看看例子。 

示例1: 

struct bf1 

; 其記憶體布局為: 

|_f1__|__f2__|_|____f3___|____| 

|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 

0 3   7 8   1316 

位域型別為char,第1個位元組僅能容納下f1和f2,所以f2被壓縮到第1個位元組中,而f3只能

從下乙個位元組開始。因此sizeof(bf1)的結果為2。 

示例2: 

struct bf2 

; 由於相鄰位域型別不同,在vc6中其sizeof為6,在dev-c++中為2。 

示例3: 

struct bf3 

; 非位域字段穿插在其中,不會產生壓縮,在vc6和dev-c++中得到的大小均為3。 

9. 聯合體的sizeof

結構體在記憶體組織上是順序式的,聯合體則是重疊式,各成員共享一段記憶體,所以整個聯

合體的sizeof也就是每個成員sizeof的最大值。結構體的成員也可以是復合型別,這裡,

復合型別成員是被作為整體考慮的。 

所以,下面例子中,u的sizeof值等於sizeof(s)。 

union u 

;

sizeof進行結構體大小的判斷

typedef struct a t typedef struct b t typedef struct c t void main s1的最寬簡單成員的型別為int,s3在考慮最寬簡單型別成員時是將s1 打散 看的,所以 s3的最寬簡單型別為int,這樣,通過s3定義的變數,其儲存空間首位址需要被...

sizeof進行結構體大小的判斷

1.2.位元組對齊原則 結構體預設的位元組對齊一般滿足三個準則 1 結構體變數的首位址能夠被其最寬基本型別成員的大小所整除 2 結構體每個成員相對於結構體首位址的偏移量 offset 都是成員大小的整數倍,如有需要編譯器會在成員之間加上填充位元組 internal adding 3 結構體的總大小為...

結構體大小sizeof的理解

在32位編譯環境中 sizeof的用法 sizeof char 1 sizeof int 4 sizeof unsigned int 4 sizeof long int 4 sizeof short int 2 sizeof float 4 sizeof double 8 2.指標變數的sizeof...