由一道面試題來(lái)看 Struct 的對(duì)界
本文節(jié)選自宋寶華的C/C++的struct深層探索一文,本人對(duì)其所描述的struct對(duì)齊比較喜歡,為此轉(zhuǎn)來(lái)與大家分享,原文見(jiàn)http://blog.donews.com/21cnbao/archive/2005/09/08/544877.aspx
Intel 、微軟等公司曾經(jīng)出過(guò)一道類似的面試題:
1. #include <iostream.h>
2. #pragma pack(8)
3. struct example1
4. {
5. short a;
6. long b;
7. };
8. struct example2
9. {
10. char c;
11. example1 struct1;
12. short e;
13. };
14. #pragma pack()
15. int main(int argc, char* argv[])
16. {
17. example2 struct2;
18. cout << sizeof(example1) << endl;
19. cout << sizeof(example2) << endl;
20. cout << (unsigned int)(&struct2.struct1) - (unsigned int)(&struct2)
<< endl;
21. return 0;
22. }
問(wèn)程序的輸入結(jié)果是什么?
答案是:
8
16
4
不明白?還是不明白?下面一一道來(lái):
1 、 自然對(duì)界
struct 是一種復(fù)合數(shù)據(jù)類型,其構(gòu)成元素既可以是基本數(shù)據(jù)類型(如 int 、 long 、 float 等)的變量,也可以是一些復(fù)合數(shù)據(jù)類型(如 array 、 struct 、 union 等)的數(shù)據(jù)單元。對(duì)于結(jié)構(gòu)體,編譯器會(huì)自動(dòng)進(jìn)行成員變量的對(duì)齊,以提高運(yùn)算效率。缺省情況下,編譯器為結(jié)構(gòu)體的每個(gè)成員按其自然對(duì)界( natural alignment )條件分配空間。各個(gè)成員按照它們被聲明的順序在內(nèi)存中順序存儲(chǔ),第一個(gè)成員的地址和整個(gè)結(jié)構(gòu)的地址相同。
自然對(duì)界 (natural alignment) 即默認(rèn)對(duì)齊方式,是指按結(jié)構(gòu)體的成員中 size 最大的成員對(duì)齊。
例如:
struct naturalalign
{
char a;
short b;
char c;
};
在上述結(jié)構(gòu)體中, size 最大的是 short ,其長(zhǎng)度為 2 字節(jié),因而結(jié)構(gòu)體中的 char 成員 a 、 c 都以 2 為單位對(duì)齊, sizeof(naturalalign) 的結(jié)果等于 6 ;
如果改為:
struct naturalalign
{
char a;
int b;
char c;
};
其結(jié)果顯然為 12 。
2 、 指定對(duì)界
一般地,可以通過(guò)下面的方法來(lái)改變?nèi)笔〉膶?duì)界條件:
· 使用偽指令 #pragma pack (n) ,編譯器將按照 n 個(gè)字節(jié)對(duì)齊;
· 使用偽指令 #pragma pack () ,取消自定義字節(jié)對(duì)齊方式。
注意:如果 #pragma pack (n) 中指定的 n 大于結(jié)構(gòu)體中最大成員的 size ,則其不起作用,結(jié)構(gòu)體仍然按照 size 最大的成員進(jìn)行對(duì)界。
例如:
#pragma pack (n)
struct naturalalign
{
char a;
int b;
char c;
};
#pragma pack ()
當(dāng) n 為 4 、 8 、 16 時(shí),其對(duì)齊方式均一樣, sizeof(naturalalign) 的結(jié)果都等于 12 。而當(dāng) n 為 2 時(shí),其發(fā)揮了作用,使得 sizeof(naturalalign) 的結(jié)果為 8 。
在 VC++ 6.0 編譯器中,我們可以指定其對(duì)界方式(見(jiàn)圖 1 ),其操作方式為依次選擇 projetct > setting > C/C++ 菜單,在 struct member alignment 中指定你要的對(duì)界方式。
圖 1 在 VC++ 6.0 中指定對(duì)界方式
另外,通過(guò) __attribute((aligned (n))) 也可以讓所作用的結(jié)構(gòu)體成員對(duì)齊在 n 字節(jié)邊界上,但是它較少被使用,因而不作詳細(xì)講解。
3 、 面試題的解答
至此,我們可以對(duì) Intel 、微軟的面試題進(jìn)行全面的解答。
程序中第 2 行 #pragma pack (8) 雖然指定了對(duì)界為 8 ,但是由于 struct example1 中的成員最大 size 為 4 ( long 變量 size 為 4 ),故 struct example1 仍然按 4 字節(jié)對(duì)界, struct example1 的 size 為 8 ,即第 18 行的輸出結(jié)果;
struct example2 中包含了 struct example1 ,其本身包含的簡(jiǎn)單數(shù)據(jù)成員的最大 size 為 2 ( short 變量 e ),但是因?yàn)槠浒?/span> struct example1 ,而 struct example1 中的最大成員 size 為 4 , struct example2 也應(yīng)以 4 對(duì)界, #pragma pack (8) 中指定的對(duì)界對(duì) struct example2 也不起作用,故 19 行的輸出結(jié)果為 16 ;
由于 struct example2 中的成員以 4 為單位對(duì)界,故其 char 變量 c 后應(yīng)補(bǔ)充 3 個(gè)空,其后才是成員 struct1 的內(nèi)存空間, 20 行的輸出結(jié)果為 4 。
在閱讀了此節(jié)之后,本人對(duì)為什么在使用過(guò)程中用sizeof取得的結(jié)構(gòu)長(zhǎng)度不同的問(wèn)題有了認(rèn)識(shí),不過(guò)本人調(diào)試時(shí),不光跟對(duì)界方式有關(guān),還和設(shè)置的Processor有關(guān),這方面還請(qǐng)大俠幫我指點(diǎn)下迷津。
過(guò)了快一年了,回過(guò)頭來(lái)再看看這篇文章發(fā)現(xiàn)還是有用的,另外再加上一句別人:當(dāng)未用 #pragma 指令指定編譯器的對(duì)齊位數(shù)時(shí),結(jié)構(gòu)體按最長(zhǎng)寬度的數(shù)據(jù)成員的寬度對(duì)齊;當(dāng)使用了#pragma 指令指定編譯器的對(duì)齊位數(shù)時(shí),結(jié)構(gòu)體按最長(zhǎng)寬度的數(shù)據(jù)成員的寬度和 #pragma 指令指定的位數(shù)中的較小值對(duì)齊。(2007年10月8日)