1. 程式人生 > >sizeof(struct{bit-field})——包含位域的結構體的空間大小

sizeof(struct{bit-field})——包含位域的結構體的空間大小

原文:sizeof(struct)

一般情況下,編譯器會把struct中的成員作對齊處理,所以sizeof後不是等於所以成員大小之和。
VC編譯器做對齊處理的步驟如下(原作者理解):
1、首先獲得struct中的大小最大的基本資料型別成員的大小,稱為記憶體分配基大小(以下簡稱:基大小),這裡的最大成員為double d1,d1的大小為8,所以基大小為8;
2、按照順序為struct中的成員分配記憶體:
(1)、分配一個大小等於基大小的記憶體;
(2)、從第一個到最後一個成員,取得每個成員的大小為N,調整可插入記憶體起始地址,使得(可插入記憶體起始地址 - struct起始地址) 為N的倍數(向後移調整),從可插入記憶體起始地址 開始插入成員,如果分配的剩餘空間大於這個成員的大小,則把struct的成員插進記憶體中,否則執行(1)。直到把所有成員插完為止。
3、此時struct的大小應該為基大小的倍數。
例如,
struct s{
    double d1;
    int d2;
    char d3;char d4;
};
記憶體分配情況如下:

8(double)+ 8(int+char+char=6)= 16

我把筆試原題深化一下,測試了一些原文沒寫到的地方(位域bit-field),過程如下:

首先是編譯器關於位域大小的區別,VC中位域大小不能大於型別大小,而Dev-C++中可以。

即 int i1:33; 在Dev-C++中合法,在VC中不合法。

因為一般在Dev-C++上寫簡短程式碼,我在這個問題浪費了很多時間,以後還是用VC吧。。

雖然沒什麼意義,還是貼出Dev-C++執行結果吧:

sizeof(struct{int i:32;})==4

sizeof(struct{int i:64;})==8

sizeof(struct{int i:65;})==16       //65

sizeof(struct{int i:128;})==16

sizeof(struct{int i:192;})==24

sizeof(struct{int i:256;})==32

可見位域大小開始每次增加4byte,8byte以後每次增加8byte(Dev-C++,48byte後未測試)

測試之前以為是像String類一樣每次翻倍(String類這樣操作可以減少空間大小變化次數,位域其實不存在這個問題,為什麼不每次都加4byte呢?)。


然後我輸出了一下每一項的地址:

struct Node
{
          char c1,c2;//2
          short s1,s2;//4
          unsigned int i1:2,i2:3;    // Node* o;  &(0->i1);發生錯誤,不能獲得位域的地址
          Node* n;//4
};//28
    
Node* o = new Node();
    
cout<<sizeof(*o)<<"\n";
cout<<"o----"<<o<<"\n";
cout<<"c1---"<<&(o->c1)<<"\n";
cout<<"c2---"<<&(o->c2)<<"\n";
cout<<"s1---"<<&(o->s1)<<"\n";
cout<<"s2---"<<&(o->s2)<<"\n";
cout<<"n----"<<&(o->n)<<"\n";

VC輸出結果為:

16

o----003GADE0

c1---??????E0

c2---??????E1

s1---??????E2//4

s2---??????E4

n----??????EC//4

Dev-C++輸出結果為:

12

o----0x??????34

c1---0x??????34

c2---0x??????35

s1---0x??????36//4

s2---0x??????38

n----0x??????4c//4

i1/i2位於s2/n之間,可以看出,VC中s2/i1/i2共佔8byte,Dev-C++中s2/i1/i2共佔4byte。(我推測VC中,s2佔2byte填為4byte,i1/i2同類型合併5bit填27bit;而Dev-C++則把s2/i1/i2填為4byte)

另外,我本來以為基會按從大到小的順序排列。(根據sizeof(struct)原文最後一段,VC不對成員作優化排列,g++對成員作優化排列)