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 時,長會對齊 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 封裝的結構可以放在任何地方,而不會造成錯誤對齊錯誤。
相關主題