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++對成員作優化排列)