c/c++結構體對齊小結

因爲我看C++對象模型的時候,遇到了幾個內存佈局都是有關於對齊的一些細節,故此對結構體對齊再做一份小結,有人說:結構體對齊這個東西是依賴於編譯器的,因此不用去研究,真的嘛?

 

也許是,也許不是,要看你是做那個行業的了,如果你是做系統地層,網絡通訊,嵌入式系統的,一個字節的節省,也許對你是很大的期望呢。雖然具體的對齊方式是因編譯器而異,但是對齊的基本原理是不變的,那個原理也許能指導我們編寫程序的時候按照某個原則去進行。

 

不過,既然你用到了C或者C++,就多數是和系統底層有緣之人了,你說是嘛?呵呵。

 

現在先說在windows x86 32位機子下的MS vs2005編譯器(就是:cl.exe for x86)下的對齊規則:

 

比如以下的結構體定義:

 

struct A

{

    int i;

    double d;

    char c;

};

 

sizeofstruct A)在vs2005的大小?

 

現在說一下cl.exe(就是微軟vs2005的編譯器進程)在默認情況下是怎麼做的:

 

1、對齊量的確定:找到A中最大的基本類型成員的大小,在本例中是8(double的大小).

 

2、當定義一個結構體變量struct A aA; 的時候,aA的起始地址要被由1確定的對齊量整除,在這個例子裏,aA的起始地址一定要能被8整除)

 

2、然後開始分配int i4字節的空間;再分配double d;注意double 8字節,所以要分配在被8整除的地方,因此int  i後面空了4字節填充;

 

3、然後,分配char c1字節,這個時候struct A的大小是4(這是int i;的) + 4 (這是填充的) + 8(這是double d;的) + 1 (這是char c;的)= 17

 

4、最後,要求結構體總的大小要能被由1確定的對齊量整除,在這裏是說struct A的大小要能被8整除,所以還要加上7字節的填充字符,一共是24字節。

 

從這裏可以看出,vs2005的編譯器的結構體填充有這樣的規則(默認情況下,這個默認情況可以通過工程屬性上面的選項修改):

 

1、對齊量的確定:結構體中最大的數據成員的字節數

 

2、當定義一個結構體變量的時候,起始地址一定能被確定的對齊量整除;

 

2、分配每一個成員的時候,該成員相對於起始地址的偏移(offset)要能被該成員的大小整除;

 

3、結構體總的大小能被確定的對齊量整除;

 

 

 

擴充的字節叫做pad(填充字節)

 

 

下面看linux g++ 3.4.3編譯器在x86 32位機子下的默認規則,那相對簡單一些:(相當於VS2005中將對齊情況改成4字節對齊)

 

對齊的方式默認是4字節,所以每個成員都按照4字節方式對齊即可。上面的結構體的大小就是:

 

4 (int i;的大小) + 8double 的大小) + 1char 的大小) + 3 (爲了4字節填充而補充的字節) = 16字節;

 

至於gcc的結構體變量的首地址分配的特徵一時也找不到,還望各位多多指教。謝謝。

 

最後,如果定義一個沒有任何成員的結構體,struct A{}; 該大小是多少呢?是1字節。如果定義了兩個結構體變量struct A a1, a2; 1字節的填充能夠使a1a2的地址區分開來!

 

還有其他的編譯器和操作系統就不是我所能知的了。

 

那麼,這些規則也許不盡相同,但是給了我們一個編程時候的注意點,就是:

 

定義結構體的時候,成員最好能從大到小來定義,那樣能相對的省空間。(至少不會比別的順序差,一般情況下哈。)

 

比如以上的結構體,如果能這樣定義:

 

struct A

{

    double d;

    int i;

    char c;

};

 

那麼,無論是windows下的vs2005,還是linux下的gcc,都是16字節。

 

對齊情況還可以通過各個編譯器給出的特性在代碼中改,不過我沒用過,就沒有發言權,各位又需要可以參考別的文章。

 

以上的過程和推論是我看別的文章和上機試驗的結果,如有不對之處,請各位指教,謝謝。

 

 

再說一點,對於有嵌套的情況,vs2005下的對齊我也不大確定,不過我的分析如下:

 

struct A

{

    char c;

    double d;

    int i;

};

 

struct B

{

    struct  A a;

    char c;

};

 

這種情況下,分析B的大小;

 

1、對齊量的確定:包括A中的各成員比較的,遞歸下去,比較各個基本類型成員的大小,去最大值,爲8(double的大小);

 

2、起始地址和上面的一樣,要求B的變量的其實地址能被8整除;

 

3、關於B中struct A a;的偏移和大小和將a單獨作爲結構體變量的時候一樣(那樣方便賦值運算)

 

剩下的和上面的規則相同;

 

所以:B的大小就是24(struct A)+ 1(char) +7(pad) = 32字節;

 

不知正確與否?還請諸位評判。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章