Alignment(對齊)
    在一個32位元的平台上,資料在4的倍數的位址上,CPU存取速度較快,這與CPU的硬體架構有關。
在一般書上,「在4的倍數的位址」通常稱為「Double word boundaries」,這是比較常見的寫法。

PS:
1的倍數的位址】稱【Byte boundary
2的倍數的位址】稱【Word boundaries
4的倍數的位址】稱【Double Word boundaries
8的倍數的位址】稱【Quad Word boundaries

    在使用structure時,為了考慮到memory alignment的問題,會衍生structure每個member alignment的問題,
要使得資料
align在所在的boundary上。
但注意
alignment不是C/C++ standard中的一部份,所以實作還是depend on compiler,一般會有這樣的規則:

【  資料大小為n,資料位址會位在(對齊,align)n的倍數上,alignmentn

這個規則的條件:Compiler的【Struct Member Alignment】大於Structure本身memberAlignment

原因會在稍後做說明,以一個例子來說明:
編譯器:Miscosoft Visual C++ 6.0
專案型態:Win32 Console Application
編譯器預設Struct Member Alignment8 bytes
(Struct Member Alignment[Project]->[Settings...]->[C/C++]:Struct Member Alignment)

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	

tagStruct中,共有4member : 
member1: sizeof(member1) = 1 , alignment 1 ,位址在1的倍數上 
member2: sizeof(member2) = 2 , alignment
2 ,位址在2的倍數上
member3: sizeof(member3) = 4 , alignment 4 ,位址在4的倍數上
member4: sizeof(member4) = 8 , alignment 8 ,位址在8的倍數上
tagStructalignmentmembersalignment最大值,即為8
對照變數
_tagStructOutput,以上的想法得到驗證。

在編譯器中有一個設定是'Struct Member Alignment',這是設定要如何align structure中每個member
structure
本身的各member,也有自己的alignment值。
編譯器會根據取'Struct Member Alignment'member本身的alignment中較小的數值,來alignmember

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.

舉個例子:

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));
} 

假設'Struct Member Alignment'8 bytes,以上的結果為:

0012FF70
0012FF78
16

這個結果可以預測,num型態為double,大小為8 bytesalignment8
所以在
member ch之後,要加上7padding之後,才使的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,而numalignment8,取較小者,為4
所以在
member ch之後,會加上3padding之後,使得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,而numalignment8,取較小者,為2
所以在
member ch之後,會加上1paddings之後,使得num Word boundaries
總共大小為
sizeof(ch) + 1 padding + sizeof(double) = 10 bytes.

假設'Struct Member Alignment'1 bytes,以上的結果為:

0012FF70
0012FF71
9

'Struct Member Alignment'1 bytes,而numalignment8,取較小者,為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
Hosted by www.Geocities.ws

1