1、字節對齊的細節和編譯器實現相關,但一般而言,如在windows下,就VC而言,滿足一下三個准則:
1) 結構體變量的首地址能夠被其最寬基本類型成員的大小所整除;
2) 結構體每個成員相對於結構體首地址的偏移量(offset)都是成員大小的整數倍,如有需要編譯器會在成員之間加上填充字節(internal adding);
即:在默認情況下,VC規定各成員變量存放的起始地址相對於結構的起始地址的偏移量:sizeof(類型)或其倍數
3) 結構體的總大小為結構體最寬基本類型成員大小的整數倍,如有需要編譯器會在最末一個成員之后加上填充字節(trailing padding)
即:最大sizeof(類型)的整數倍
類型
對齊方式(變量存放的起始地址相對於結構的起始地址的偏移量)
Char 偏移量必須為sizeof(char)即1的倍數
int 偏移量必須為sizeof(int)即4的倍數
float 偏移量必須為sizeof(float)即4的倍數
double 偏移量必須為sizeof(double)即8的倍數
Short 偏移量必須為sizeof(short)即2的倍數
簡單說明:
struct DoNothing
{
};
這個sizeof(DoNothing)肯定是1的,原因是一個“沒有空間”的變量如何去取它的地址呢?如果有兩個不同的空struct如何去區分它們呢?這樣編譯器就只好這么處理了。
struct MyStruct
{
char dda; //偏移量為0,滿足對齊方式,dda占用1個字節;
double dda1; //下一個可用的地址的偏移量為1,不是sizeof(double)=8的倍數,需要補足7個字節才能使偏移量變為8(滿足對齊方式),因此VC自動填充7個字節,dda1存放在偏移量為8的地址上,它占用8個節。
int type; //下一個可用的地址的偏移量為16,是sizeof(int)=4的倍數,滿足int的對齊方式,所以不需要VC自動填充,type存/放在偏移量為16的地址上,它占用4個字節。
};//所有成員變量都分配了空間,空間總的大小為1 7 8 4=20,不是結構的節邊界數(即結構中占用最大空間的類型所占用的字節數sizeof 字串2(double)=8)的倍數,所以需要填充4個字節,以滿足結構的大小為sizeof(double)=8的倍數。
所以該結構總的大小為:sizeof(MyStruc)為1 7 8 4 4=24。其中總的有7 4=11個字節是VC自動填充的,沒有放任何有意義的東西。
2、如何修改編譯器的默認對齊值?
1.在VC IDE中,可以這樣修改:[Project]|[Settings],c/c++選項卡Category的Code Generation選項的Struct Member Alignment中修改,默認是8字節。
2.在編碼時,可以這樣動態修改:#pragma pack .注意:是pragma而不是progma.
1) n字節對齊就是說變量存放的起始地址的偏移量有兩種情況:第一、如果n大於等於該變量所占用的字節數,那么偏 移量必須滿足默認的對齊方式,第二、如果n小於該變量的類型所占用的字節數,那么偏移量為n的倍數,不用滿足默認的對齊方式。
2) 結構的總大小也有個約束條 件,分下面兩種情況:如果n大於所有成員變量類型所占用的字節數,那么結構的總大小必須為占用空間最大的變量占用的空間數的倍數,否則是n的倍數。
總結,struct的大小通過以下兩點即可得出:
1.數據成員對齊規則:
n字節對齊就是說變量存放的起始地址的偏移量:min(sizeof(類型),對齊方式)或其倍數.
2.整體對齊規則:
結構的總大小也有個約束條件:min(最大的sizeof(類型),對齊方式)的倍數.
下面舉例說明其用法。
#pragma pack(push) //保存對齊狀態
#pragma pack(4)//設定為4字節對齊
struct test
{
char m1;
double m4;
int m3;
};
#pragma pack(pop)//恢復對齊狀態
以上結構的大小為16,下面分析其存儲情況,首先為m1分配空間,其偏移量為0,滿足我們自己設定的對齊方式(4字節對齊),m1占用1個字節。接着開始為 m4分配空間,這時其偏移量為1,需要補足3個字節,這樣使偏移量滿足為n=4的倍數(因為sizeof(double)大於n),m4占用8個字節。接 着為m3分配空間,這時其偏移量為12,滿足為4的倍數,m3占用4個字節。這時已經為所有成員變量分配了空間,共分配了16個字節,滿足為n的倍數。如 果把上面的#pragma pack(4)改為#pragma pack(16),那么我們可以得到結構的大小為24。
3、Union
union的長度取決於其中的長度最大的那個成員變量的長度。即union中成員變量是重疊擺放的,其開始地址相同。
其實union(共用體)的各個成員是以同一個地址開始存放的,每一個時刻只可以存儲一個成員,這樣就要求它在分配內存單元時候要滿足兩點:
1.一般而言,共用體類型實際占用存儲空間為其最長的成員所占的存儲空間;
2.若是該最長的存儲空間對其他成員的元類型(如果是數組,取其類型的數據長度,例int a[5]為4)不滿足整除關系,該最大空間自動延伸;
我們來看看這段代碼:
union mm{
char a;//元長度1
int b[5];//元長度4
double c;//元長度8
int d[3]; //元長度4
};
本來mm的空間應該是sizeof(int)*5=20;但是如果只是20個單元的話,那可以存幾個double型(8位)呢?兩個半?當然不可以,所以mm的空間延伸為既要大於20,又要滿足其他成員所需空間的整數倍,,因為含有double元長度8,故大小為24。
所以union的存儲空間先看它的成員中哪個占的空間最大,拿他與其他成員的元長度比較,如果可以整除就行。
thx for:
http://www.cnblogs.com/alexkk2011/archive/2011/03/30/2000057.html
http://hi.baidu.com/gaomanyi/blog/item/9cf279638b96cb660d33fad0.html