align
(C++)
在 Visual Studio 2015 和更新版本中,使用 alignas
規範 (C++11) 來控制對齊。 如需詳細資訊,請參閱 對齊方式。
Microsoft 特定的
使用 __declspec(align(#))
可精確控制使用者定義資料的對齊 (例如,靜態配置或函式中的自動資料)。
語法
__declspec(align(#) )宣告子
備註
撰寫使用最新處理器指令的應用程式會帶來一些新的限制和問題。 許多新指示都需要數據對齊 16 位元組界限。 將常用數據對齊處理器的快取行大小,可改善快取效能。 例如,如果您定義大小小於 32 個字節的結構,您可能會想要 32 位元組對齊,以確保該結構類型的物件有效率地快取。
# 是對齊值。 有效項目是從 1 至 8192 (位元組) 的 2 乘冪整數,例如 2、4、8、16、32 或 64。 declarator
是您宣告為對齊的數據。
如需如何傳回型 size_t
別值的相關信息,該值是型別的對齊需求,請參閱 alignof
。 如需如何在以 64 位處理器為目標時宣告未對齊指標的資訊,請參閱 __unaligned
。
您可以在定義struct
、union
、 或 class
時使用__declspec(align(#))
,或宣告變數時使用。
編譯程式不保證或嘗試在複製或數據轉換作業期間保留數據的對齊屬性。 例如, memcpy
可以將 宣告 __declspec(align(#))
的結構複製到任何位置。 一般配置器(例如,、 malloc
C++ operator new
和 Win32 配置器)通常會傳回未對齊 __declspec(align(#))
結構或結構陣列的記憶體。 若要保證複製或資料轉換作業的目的地已正確對齊,請使用 _aligned_malloc
。 或者,撰寫您自己的配置器。
您無法指定函式參數的對齊方式。 當您依值在堆疊上傳遞具有對齊屬性的數據時,呼叫慣例會控制其對齊方式。 如果資料對齊在呼叫的函式中很重要,請將參數複製到正確對齊的記憶體中,才使用該參數。
如果沒有 __declspec(align(#))
,編譯程式通常會根據目標處理器和數據大小,在32位處理器上對齊自然界限的數據,以及64位處理器上的8位元組界限。 類別或結構中的數據會在其自然對齊和目前的封裝設定(或#pragma pack
/Zp
編譯程序選項)下限對齊類別或結構中。
這個範例會示範 __declspec(align(#))
的使用方式。
__declspec(align(32)) struct Str1{
int a, b, c, d, e;
};
這個類型現在具有 32 位元組對齊屬性。 這表示所有靜態和自動實例都會在32位元組界限上啟動。 以這個類型宣告為成員的其他結構類型會保留此類型的對齊屬性。 也就是說,具有 Str1
做為 元素的任何結構都有至少 32 的對齊屬性。
在這裡, sizeof(struct Str1)
等於 32。 這表示如果建立對象的陣列 Str1
,而且陣列的基底對齊 32 位元組,則陣列的每個成員也會對齊 32 位元組。 若要建立基底在動態記憶體中正確對齊的陣列,請使用 _aligned_malloc
。 或者,撰寫您自己的配置器。
任何結構的 sizeof
值都是最後一個成員的位移,加上該成員的大小,然後捨入至最大成員對齊值或整個結構對齊值 (以較大者為準) 的最接近倍數。
編譯器會為結構對齊使用這些規則:
除非以
__declspec(align(#))
覆寫,否則純量結構成員的對齊是其大小與目前封裝的最小值。除非以
__declspec(align(#))
覆寫,否則結構的對齊是其成員的個別對齊最大值。結構成員位於其父結構開頭的位移,其對齊範圍中最小倍數大於或等於前一個成員結尾的位移。
結構的大小是其對齊的最小倍數 (大於或等於其最後一個成員結尾的位移)。
__declspec(align(#))
只能增加對齊限制。
如需詳細資訊,請參閱
align
範例
下列範例說明 __declspec(align(#))
如何影響資料結構的大小和對齊。 這個範例會假設下列定義:
#define CACHE_LINE 32
#define CACHE_ALIGN __declspec(align(CACHE_LINE))
在這個範例中,S1
結構使用 __declspec(align(32))
定義。 針對變數定義使用的所有 S1
,或其他類型宣告中,都是對齊 32 位元組。 sizeof(struct S1)
會傳回 32,而且 S1
在保留四個整數所需的 16 個位元組後面會有 16 個填補位元組。 每個 int
成員都需要 4 位元組對齊,但結構本身的對齊方式宣告為 32。 然後整體對齊為 32。
struct CACHE_ALIGN S1 { // cache align all instances of S1
int a, b, c, d;
};
struct S1 s1; // s1 is 32-byte cache aligned
在下列範例中,sizeof(struct S2)
會傳回 16,也就是成員大小的總和,因為這剛好是最大對齊需求的倍數 (8 倍)。
__declspec(align(8)) struct S2 {
int a, b, c, d;
};
在下列範例中,sizeof(struct S3)
會傳回 64。
struct S3 {
struct S1 s1; // S3 inherits cache alignment requirement
// from S1 declaration
int a; // a is now cache aligned because of s1
// 28 bytes of trailing padding
};
在這個範例中,請注意 a
有其自然類型的對齊,在此情況下,為 4 個位元組。 不過,S1
必須對齊 32 位元組。 28 個字節的填補後面 a
,因此 s1
從位移 32 開始。 S4
接著會繼承 的 S1
對齊需求,因為它是 結構中最大的對齊需求。 sizeof(struct S4)
會傳回 64。
struct S4 {
int a;
// 28 bytes padding
struct S1 s1; // S4 inherits cache alignment requirement of S1
};
下列三個變數宣告也會使用 __declspec(align(#))
。 在每個案例中,變數必須對齊 32 位元組。 在陣列中,陣列的基位址,而非每個陣列成員,會對齊32位元組。 sizeof
當您使用 __declspec(align(#))
時,每個陣列成員的值不會受到影響。
CACHE_ALIGN int i;
CACHE_ALIGN int array[128];
CACHE_ALIGN struct s2 s;
若要對齊陣列的每個成員,應使用如下的程式碼:
typedef CACHE_ALIGN struct { int a; } S5;
S5 array[10];
在這個範例中,請注意對齊結構本身和對齊第一個元素都有相同的效果:
CACHE_ALIGN struct S6 {
int a;
int b;
};
struct S7 {
CACHE_ALIGN int a;
int b;
};
S6
和 S7
具有相同的對齊、配置和大小特性。
在此範例中,、 b
c
和 d
的起始位址a
對齊方式分別為 4、1、4 和 1。
void fn() {
int a;
char b;
long c;
char d[10]
}
如果已在堆積上配置記憶體,則對齊會取決於所呼叫的配置函式。 例如,如果您使用 malloc
,則結果會取決於運算元大小。 如果 arg>= 8,傳回的記憶體會對齊 8 位元組。 如果 arg< 8,傳回的記憶體對齊方式是 2 小於 arg 的第一個功率。 例如,如果您使用 malloc(7)
,對齊方式為 4 個字節。
使用定義新類型 __declspec(align(#))
您可以定義具有對齊特性的類型。
例如,您可以透過下列方式,使用對齊值來定義 struct
:
struct aType {int a; int b;};
typedef __declspec(align(32)) struct aType bType;
現在和 aType
bType
的大小相同(8 個字節),但 類型的 bType
變數會對齊 32 位元組。
對齊線程本機記憶體中的數據
使用 __declspec(thread)
屬性建立並放入影像之 TLS 區段的靜態執行緒區域儲存區 (TLS) 可用於對齊,就像一般靜態資料一樣。 為了建立 TLS 資料,作業系統會配置記憶體的 TLS 區段大小,並接受 TLS 區段對齊屬性。
此範例示範各種將對齊的資料放入執行緒區域儲存區中的方式。
// put an aligned integer in TLS
__declspec(thread) __declspec(align(32)) int a;
// define an aligned structure and put a variable of the struct type
// into TLS
__declspec(thread) __declspec(align(32)) struct F1 { int a; int b; } a;
// create an aligned structure
struct CACHE_ALIGN S9 {
int a;
int b;
};
// put a variable of the structure type into TLS
__declspec(thread) struct S9 a;
如何使用 align
數據封裝
編譯 /Zp
程式選項和 pack
pragma 對於結構和等位成員封裝數據的效果。 此範例示範如何 /Zp
和 __declspec(align(#))
一起運作:
struct S {
char a;
short b;
double c;
CACHE_ALIGN double d;
char e;
double f;
};
下表列出每個 /Zp
成員在不同 (或 #pragma pack
) 值下的位移,其中顯示這兩個成員的互動方式。
變數 | /Zp1 | /Zp2 | /Zp4 | /Zp8 |
---|---|---|---|---|
a | 0 | 0 | 0 | 0 |
b | 1 | 2 | 2 | 2 |
c | 3 | 4 | 4 | 8 |
d | 32 | 32 | 32 | 32 |
e | 40 | 40 | 40 | 40 |
f | 41 | 42 | 44 | 48 |
sizeof(S) | 64 | 64 | 64 | 64 |
如需詳細資訊,請參閱/Zp
(結構成員對齊方式)。
因此,物件的位移是根據前一個物件的位移與目前封裝設定,但如果物件具有 __declspec(align(#))
屬性,情況就不是這樣,此時對齊是根據前一個物件的位移與物件的 __declspec(align(#))
值。
END Microsoft 特定的
另請參閱
意見反應
https://aka.ms/ContentUserFeedback。
即將登場:在 2024 年,我們將逐步淘汰 GitHub 問題作為內容的意見反應機制,並將它取代為新的意見反應系統。 如需詳細資訊,請參閱:提交並檢視相關的意見反應