C 編譯程式封裝問題
封裝層級會以相同方式影響 MIDL 和 Microsoft C/C++ 編譯程式的記憶體配置。 在Microsoft建置環境中,例如 VC++ 或平臺軟體開發工具包 (SDK) 所定義的組建環境,MIDL 和 C/C++ 編譯程式的預設封裝層級相同:32 位和 64 位 Windows 組建環境的預設封裝層級為 8。
自然對齊
針對記憶體中的類型,預設對齊方式與其自然對齊方式相同。
- 基本類型,例如 short、float 和 __int64,以及指標,如果其表示從一個地址開始,並且該地址是大小的倍數,那麼它們就會自然對齊。 目前所有支援的基底類型大小為 1、2、4 或 8。 指標的大小在32位環境中為4,在64位環境中為8。
- 如果每個元件與型別的開頭自然對齊,而且元件之間沒有不必要的間距(填補),復合類型就會自然對齊。 複合元件,例如欄位或元素,會遞歸至指標或基底類型元件。
協助記住此行為的簡單規則是,類型的自然對齊方式等於其元件的最大對齊方式。
在像 C 或 C++ 和 IDL 這樣的語言中,數據類型的對齊方式和記憶體大小之間存在關係,這由運算子 sizeof()所表達。 大小是對齊方式的倍數(涵蓋類型的最小對齊倍數)。 這是基於記憶體中的陣列表示法。
自然對齊很重要,因為存取未對齊的數據可能會導致某些系統上的例外狀況。 當數據不對齊時,可以被標記為可安全操作,但通常這樣做會在某些平臺上造成顯著的速度影響。
注意
在記憶體中,具有自然對齊属性的類型物件 n,保證在位於如 n的倍數的位址上時,能夠正確對齊。
封裝與對齊
指定大於類型自然對齊的封裝層級並不會變更類型對齊方式。 指定小於自然對齊的封裝層級會減少封裝層級的型別對齊。 因此,封裝類型可能會放在記憶體中的位址,這些位址是封裝層級的倍數(減少對齊方式),而不會造成不對齊。 這會影響簡單類型和元件類型。 對於複合類型,型別的內部佈局可能會受到影響,因為元件的對齊減少可能改變元件適當對齊所需的填補大小,從而減少類型的大小。
用來協助記住此行為的簡單規則是,封裝類型新的對齊方式是封裝層級與其自然對齊方式中較小者。 型別的大小是新對齊的倍數。 sizeof() 運算符會傳回包裝類型的縮減大小。
例如,在封裝層級 2 時,long 會對齊到 2,因此可能會放置在任何偶數位址,而不是像自然對齊那樣僅限於 4 的倍數位址。 結構,短和長,包裝在 2,不需要短到下列長之間的內部間距,這是自然對齊的必要:因此,結構現在不僅對齊在 2,而且其大小也從 8 減少到 6。
例如,假設複合類型包含1位元組位元、整數4個字節長,以及1位元組字元:
struct mystructtype
{
char c1; /* requires 1 byte */
/* 3 bytes of padding with natural alignment only */
long l2; /* requires 4 bytes */
char c3; /* requires 1 byte */
/* 3 bytes of padding with natural alignment only */
} mystruct;
此結構自然對齊 4,且大小為 12。
對於封裝層級 4 或更大,結構 mystruct 會對齊到 4 字節,且 sizeof(struct mystructtype)
等於 12。 如果位於不是 4 倍數的位址的記憶體中,結構將會不對齊。
針對封裝層級 2,結構會對齊於 2 位元,其大小為 8 位元。 如果位於不是 2 倍數之位址的記憶體中,則包裝層級 2 的結構會錯誤對齊。
針對封裝層級 1,結構將以 1 進行對齊,其大小為 6。 填充於層級 1 的結構可以放在任何地方,而不會造成歪斜錯誤。
相關主題