結(jié)構(gòu)體對(duì)齊那點(diǎn)事 熟練c/c++(四)
剛剛完成一個(gè)文件的遷移程序,其中遇到了結(jié)構(gòu)體對(duì)齊的問題,所以拿出來說說,與各位博友們分享。
我的程序很簡(jiǎn)單,就是把之前通過一個(gè)結(jié)構(gòu)體fwrite到文件A里的內(nèi)容讀出,然后轉(zhuǎn)給另一個(gè)結(jié)構(gòu)體保存。程序是簡(jiǎn)單,但我擔(dān)心的是之前把結(jié)構(gòu)體fwrite到文件A的程序?qū)R結(jié)構(gòu)體規(guī)則是怎樣的?一定要知道它嗎? 當(dāng)然了,如果那個(gè)程序結(jié)構(gòu)體是按照1對(duì)齊寫入的,我的程序結(jié)構(gòu)體是按照4對(duì)齊讀入,那不就糟了!
這里我引入結(jié)構(gòu)體對(duì)齊的概念,也可以說是內(nèi)存對(duì)齊了。為什么要內(nèi)存對(duì)齊呢,就是方便CPU尋址了,具體原因大家要參考計(jì)算機(jī)體系結(jié)構(gòu)了。先看一個(gè)內(nèi)存對(duì)齊的例子:
struct example1{
char a;
double b;
long l;
};
struct example2{
char a;
long l;
double b;
};
大家算算結(jié)構(gòu)體大小,初次接觸的博友可能對(duì)答案有點(diǎn)驚訝,VC編譯, sizeof后結(jié)果分別是:24,16。 同樣是的結(jié)構(gòu)體,成員換了順序,大小就不同了。其實(shí)內(nèi)存對(duì)齊有個(gè)規(guī)則,只要知道了,就OK。那么以下5點(diǎn)是關(guān)鍵
1. 內(nèi)存對(duì)齊與編譯器設(shè)置有關(guān),首先要搞清編譯器這個(gè)默認(rèn)值是多少
2. 如果不想編譯器默認(rèn)的話,可以通過#pragma pack(n)來指定按照n對(duì)齊
3. 每個(gè)結(jié)構(gòu)體變量對(duì)齊,如果對(duì)齊參數(shù)n(編譯器默認(rèn)或者通過pragma指定)大于該變量所占字節(jié)數(shù)(m),那么就按照m對(duì)齊,內(nèi)存偏移后的地址是m的倍數(shù),否則是按照n對(duì)齊,內(nèi)存偏移后的地址是n的倍數(shù)。也就是最小化長(zhǎng)度規(guī)則
4. 結(jié)構(gòu)體總大小: 對(duì)齊后的長(zhǎng)度必須是成員中最大的對(duì)齊參數(shù)的整數(shù)倍。最大對(duì)齊參數(shù)是從第三步得到的。
5. 補(bǔ)充:如果結(jié)構(gòu)體A中還要結(jié)構(gòu)體B,那么B的對(duì)齊方式是選它里面最長(zhǎng)的成員的對(duì)齊方式
所以計(jì)算結(jié)構(gòu)體大小要走三步,首先確定是當(dāng)前程序按照幾對(duì)齊(參照1,2點(diǎn)),接著計(jì)算每個(gè)結(jié)構(gòu)體變量的大小和偏移(參照3,5),最后計(jì)算結(jié)構(gòu)體總大小(參照4)。
先算算example1吧,假設(shè)編譯器是以16對(duì)齊的
1.確定按照幾對(duì)齊: 16;
2.確定每個(gè)成員的偏移:a 占一個(gè)字節(jié),16>1, 按照1對(duì)齊,起始位置0,0%1 = 0,那么a就存在0位置;b占8個(gè)字節(jié),16>8,按照8對(duì)齊,起始位置就不能是1了,因?yàn)橐凑?/span>8對(duì)齊,所以最近的偏移起始位置是8, 8%8 =0, 那么b就存在位置8-15的位置;l占4個(gè)字節(jié),16>4,按照4對(duì)齊,起始位置16, 16%4=0,那么l就存在位置16-19的位置。所以結(jié)構(gòu)體從0到19一共占用20個(gè)字節(jié)
3.結(jié)構(gòu)體總大小:成員中最大的對(duì)齊參數(shù)是b的8對(duì)齊,所以20%8!=0, 24剛好。
真的很搞!同理計(jì)算example2應(yīng)該是16;
再舉個(gè)結(jié)構(gòu)體嵌套的例子吧,
#pragma pack(push)
#pragma pack(8)
struct test1{
int a;
char b;
int c[20]
long l;
} ;
struct test2{
char a1;
char a2;
struct test1 t1;
double b1;
}
#pragma pack(pop)
先計(jì)算test1, 8對(duì)齊,a占用0-3,b占用4,c占用8-87,l占用88-91,一共92個(gè)字節(jié)。成員中最大的對(duì)齊參數(shù)是int了92%4=0;
再計(jì)算test2, a1z占用0,a2占用1,t1呢,4 % 4 (test1里面最長(zhǎng)的成員的對(duì)齊方式) = 0, 4-95,b1占96到103;一共104個(gè)字節(jié),成員中最大的對(duì)齊參數(shù)是double了104%8=0; 所以是104.
那關(guān)于我文章開頭提到的那個(gè)文件轉(zhuǎn)換,我現(xiàn)在只要知道原始程序是按照什么對(duì)齊的,然后在新程序中指定按照幾對(duì)齊就可以了,哈哈!
擠時(shí)間寫的,有的地方有遺漏,請(qǐng)各位指正!
posted on 2009-01-06 23:39 攀升 閱讀(8859) 評(píng)論(9) 編輯 收藏 引用 所屬分類: C/C++