Alignment(對齊)
在使用structure時,為了考慮到memory
alignment的問題,會衍生structure每個member
alignment的問題,
要使得資料align在所在的boundary上。
但注意alignment不是C/C++
standard中的一部份,所以實作還是depend
on compiler,一般會有這樣的規則:
【 資料大小為n,資料位址會位在(對齊,align)n的倍數上,alignment為n
】
這個規則的條件:Compiler的【Struct
Member Alignment】大於Structure本身member的Alignment。
原因會在稍後做說明,以一個例子來說明:
編譯器:Miscosoft Visual C++ 6.0
專案型態:Win32 Console
Application
編譯器預設Struct Member Alignment為8
bytes
(Struct Member Alignment在[Project]->[Settings...]->[C/C++]:Struct
Member Alignment)
在tagStruct中,共有4個member :code:
#include <stdio.h> struct tagStruct { char member1; short int member2; long int member3; double member4; }; void main() { struct tagStruct _tagStruct; printf("%p\n",&_tagStruct.member1); printf("%p\n",&_tagStruct.member2); printf("%p\n",&_tagStruct.member3); printf("%p\n",&_tagStruct.member4); printf("%d\n",sizeof(struct tagStruct)); }Output: 0012FF70 0012FF72 0012FF74 0012FF78 16
在編譯器中有一個設定是'Struct
Member Alignment',這是設定要如何align
structure中每個member。
而structure本身的各member,也有自己的alignment值。
編譯器會根據取'Struct Member Alignment'及member本身的alignment中較小的數值,來align該member。
MSDN的說明如下:
The Struct Member Alignment (/Zpn) option controls how the members of a structure are packed into memory
and specifies the same packing for all structures in a module. When you specify this option, each structure member
after the first is stored on either the size of the member type or n-byte boundaries (where n is 1, 2, 4, 8, or 16),
whichever is smaller.
舉個例子:
假設'Struct Member Alignment'為8 bytes,以上的結果為:code:
#include<stdio.h> struct tagStruct { char ch; double num; }; void main() { struct tagStruct _tagStruct; printf("%p\n",&_tagStruct.ch); printf("%p\n",&_tagStruct.num); printf("%d\n",sizeof(struct tagStruct)); }
這個結果可以預測,num型態為double,大小為8
bytes, alignment為8。
所以在member ch之後,要加上7個padding之後,才使的num
Quad-word boundaries。
總共的大小為 sizeof(ch) + 7 paddings +
sizeof(double) = 16 bytes.
假設'Struct Member Alignment'為4 bytes,以上的結果為:
0012FF70
0012FF74
12
'Struct Member Alignment'為4
bytes,而num的alignment為8,取較小者,為4。
所以在member ch之後,會加上3個padding之後,使得num
Double word boundaries。
總共的大小為 sizeof(ch) + 3 paddings +
sizeof(double) = 12 bytes.
假設'Struct Member Alignment'為2 bytes,以上的結果為:
0012FF70
0012FF72
10
'Struct Member Alignment'為2
bytes,而num的alignment為8,取較小者,為2。
所以在member ch之後,會加上1個paddings之後,使得num
Word boundaries。
總共大小為 sizeof(ch) + 1 padding +
sizeof(double) = 10 bytes.
假設'Struct Member Alignment'為1 bytes,以上的結果為:
0012FF70
0012FF71
9
'Struct Member Alignment'為1
bytes,而num的alignment為8,取較小者,為1。
所以在member ch之後,直接連結member
num
總共大小為 sizeof(ch) + sizeof(double) =
9 bytes.
PS:
在調整"Struct
Member Alignment"時,可能會出現以下的警告訊息:
warning C4653: compiler option 'structure packing (/Zp)' inconsistent with precompiled header; current command-line option ignored
這表示,compiler
option設定的"Struct
Member Alignment"與Precompiled
header中的數值不一致,產生衝突
所以compiler忽略了"Struct
Member Alignment"的數值,而以Precompiled
header中的數值。
Precompiled header中的"Struct
Member Alignment"的數值應該為8
bytes。
此時若要讓Compiler的設定生效的話,請把Precompiled
header關掉,方法如下:
[Project]->[Settings...]->[C/C++]:[Category]:<Precompiled
Headers>:
選擇【Not
using precompiled headers】
以上利用VC++ 6.0中的設定來說明Struct
Member Alignment的觀念,在實際的運用上,並不建議直接更改
Compiler "Struct Member Alignment"的數值,因為這樣會影響到整個程式的效率。還記得一開始說,在32
位元平台上,Double word boundaries,
CPU讀取速度較快,所以除非有必要或十分清楚使用的方法,不建議
自行調整Alignment,而是自動以Compiler的設定為主。
另一種調整"Struct
Member Alignment"的方法,可以參考:
pragma(Visual
C++) - #pragma pack( show [n] )
Written By James On 2004/09/09