本來,一般是不自己計(jì)算sizeof的,知道內(nèi)存對齊會對sizeof有影響,所以從來不手算,而是代碼里寫上sizeof。今天又看到
http://blog.vckbase.com/smileonce/archive/2005/08/08/10658.html,翻來了
http://blog.vckbase.com/billdavid/archive/2004/06/23/509.html ,自己想想還是也記錄一下,萬一以后自己真的也要計(jì)算sizeof,忘了,還能有個提示,也給不是很明白的朋友一個參考。
struct sample1
{
char a; /// sizeof(char) = 1
double b; /// sizeof(double) = 8
};
///default( 缺省#pragam pack(8) ——VC6和VC71,其它編譯器,個人未知 )
///1+8 = 9 —> 16( 8 < 9 < 16 )#pragma pack( 4 )
///1+8 = 9 —> 12( 8 < 9 < 12 )
#pragma pack( 2 )
///1+8 = 9 —> 10( 8 < 9 < 10 )
#pragma pack( 1 )
///1+8 = 9 —> 9
#pragma pack( 16 )
///1+8 = 9 —> 16( 16—>8 ---- 8 < 9 < 16 )
struct sample2
{
char a; ///1
int b; ///4
};
#pragma pack( 8 )
/// 1 + 4 = 5 —> 8( 8 —> 4 )
#pragma pack( 16 )
/// 1 + 4 = 5 —> 8( 16 —> 4 )
說明:#pragma pack告訴編譯器進(jìn)行內(nèi)存邊界對齊,一般都是采用編譯器的設(shè)置對整個項(xiàng)目采用同一對齊方案,而且通常為缺省8字節(jié)對齊。
/////////////////////////////////以下內(nèi)容于 2005-12-10 添加///////////////////////////////// 今天又看到以前測試的一段代碼,突然不明白了起來,又稍寫了幾個測試。
struct sample3
{
char a; ///1
int b; ///4
char c; ///1
};
///default
///12#pragma pack( 4 )
///12#pragma pack( 2 )
///08#pragma pack( 1 )
///06#pragma pack( 16 )
///12 原來,其實(shí)編譯器,根據(jù)對齊指示的對齊字節(jié)和最大成員的字節(jié),對每個成員進(jìn)行了對齊:編譯器會取對齊指示和最大成員字節(jié)中較小的一個用于補(bǔ)齊其它成員。那么,上面的sample1/2/3也就都在情理之中了。為了證實(shí)這點(diǎn),我們還再看一個例子:
struct sample4
{
char a; ///1
int b; ///4
double c; ///8
char d; ///1
};
///default:
///8+8+8+8 = 32#pragma pack( 4 )
///4+4+8+4 = 20#pragma pack( 2 )
///2+4+8+2 = 16#pragma pack( 1 )
///1+4+8+1 = 14#pragma pack( 16 )
///8+8+8+8 = 32而實(shí)際上,編譯器給出的值是:
24、20、16、14、24那么說明我錯了。注意一下,我發(fā)現(xiàn)char a,int b加起來也才5<8,難到編譯器進(jìn)行了聯(lián)合對齊?
struct sample5
{
char a; ///1
double c; ///8
int b; ///4
char d; ///1
};
編譯器給出結(jié)果:
24、20、16、14、24 這用聯(lián)合對齊的解釋正好符合,我又試驗(yàn)了不同的數(shù)據(jù),發(fā)現(xiàn)這個結(jié)論并不太準(zhǔn)確確。于是,我輸出了每一個對象成員地址進(jìn)行分析。由于試驗(yàn)數(shù)據(jù)量很大,這里就不列出了。
最后得到了以下結(jié)論:
1. 成員的對齊是按聲明順序進(jìn)行的;
2. 對齊值由編譯指示和最大成員兩者較小的值決定;
3. 未對齊到對齊值的成員一起形成塊對齊(聯(lián)合對齊);
4. 上一個(下一個)對齊采用自己較大則不變,自己較小則填充自己對齊到上一個(下一個)大??;
5. 每成員對齊:如果前面已對齊到對齊值,下一個對齊自己。如果前面未對齊到對齊值,如果加上下一個成員不大于對齊值,下一個對齊自己,否則填充自己塊對齊到對齊值。
6. 最后還未對齊到對齊值的,填充空間塊對齊到對齊值。
從這些結(jié)論,可以得到:
1. 以上的對齊原則其實(shí)是盡量整齊排列、盡量節(jié)省內(nèi)存。
2. 聲明成員應(yīng)該盡量避免不同類型錯雜開來,最好采用從小到大或者從大到小的順序(錯開后,會因?yàn)樯蠈R和下對齊而增加填充開銷)。
3. 編譯器缺省采用8字節(jié)對齊主要是因?yàn)樽畲蠡绢愋蜑?自己(以前自己不明白,在論壇提過問,后來,以為是SSE指令的原因)。
4. 手算sizeof是沒有必要的,負(fù)責(zé)的(可以先對齊出對齊塊,用塊數(shù)乘對齊值)。