align (C++)

Verwenden Sie alignas in Visual Studio 2015 und höher den Bezeichner (C++11), um die Ausrichtung zu steuern. Weitere Informationen finden Sie unter "Ausrichtung".

Microsoft-spezifisch

Verwenden Sie __declspec(align(#)), um die Ausrichtung von benutzerdefinierten Daten genau zu steuern (z. B. statische Speicherbelegungen oder automatische Daten in einer Funktion.)

Syntax

__declspec( align(#) )deklarator

Hinweise

Das Schreiben von Anwendungen, die die neuesten Prozessoranweisungen verwenden, bringt mehrere neue Einschränkungen und Probleme mit sich. Viele neue Anweisungen erfordern, dass Daten an 16-Byte-Grenzen ausgerichtet werden. Das Ausrichten häufig verwendeter Daten an die Cachezeilengröße des Prozessors verbessert die Cacheleistung. Wenn Sie z. B. eine Struktur definieren, deren Größe kleiner als 32 Byte ist, möchten Sie möglicherweise eine 32-Byte-Ausrichtung verwenden, um sicherzustellen, dass Objekte dieses Strukturtyps effizient zwischengespeichert werden.

#ist der Ausrichtungswert. Gültige Einträge sind ganzzahlige Potenzen von zwei von 1 bis 8192 (Bytes), z. B. 2, 4, 8, 16, 32 oder 64. declarator sind die Daten, die Sie als ausgerichtet deklarieren.

Informationen zum Zurückgeben eines Typwerts size_t , der die Ausrichtungsanforderung des Typs darstellt, finden Sie unter alignof. Informationen zum Deklarieren von nicht ausgerichteten Zeigern für 64-Bit-Prozessoren finden Sie unter __unaligned.

Sie können verwenden __declspec(align(#)) , wenn Sie eine structVariable uniondefinieren, oder classwenn Sie eine Variable deklarieren.

Der Compiler garantiert nicht, oder versucht, das Ausrichtungsattribut von Daten während eines Kopier- oder Datentransformationsvorgangs beizubehalten. Beispielsweise memcpy kann eine struktur deklarierte Struktur __declspec(align(#)) an einen beliebigen Speicherort kopiert werden. Gewöhnliche Allokatoren (z malloc. B. C++ operator newund win32-Allokatoren) geben in der Regel Speicher zurück, der nicht für __declspec(align(#)) Strukturen oder Arrays von Strukturen ausgerichtet ist. Um sicherzustellen, dass das Ziel eines Kopier- oder Datentransformationsvorgangs korrekt ausgerichtet ist, verwenden Sie _aligned_malloc. Oder schreiben Sie Ihren eigenen Zuweisungsgeber.

Sie können die Ausrichtung für Funktionsparameter nicht angeben. Wenn Sie Daten übergeben, die über ein Ausrichtungsattribut nach Wert im Stapel verfügen, steuert die aufrufende Konvention die Ausrichtung. Falls die Datenausrichtung in der aufgerufenen Funktion wichtig ist, kopieren Sie vor der Verwendung den Parameter in den korrekt ausgerichteten Speicher.

Der __declspec(align(#))Compiler richtet daten in der Regel auf der Grundlage des Zielprozessors und der Größe der Daten, bis zu 4-Byte-Begrenzungen auf 32-Bit-Prozessoren und 8-Byte-Begrenzungen auf 64-Bit-Prozessoren aus. Daten in Klassen oder Strukturen werden in der Klasse oder Struktur mindestens der natürlichen Ausrichtung und der aktuellen Verpackungseinstellung (von #pragma pack oder der /Zp Compileroption) ausgerichtet.

In diesem Beispiel wird die Verwendung von __declspec(align(#)) veranschaulicht:

__declspec(align(32)) struct Str1{
   int a, b, c, d, e;
};

Dieser Typ verfügt nun über ein 32-Byte-Ausrichtungsattribut. Dies bedeutet, dass alle statischen und automatischen Instanzen auf einer Grenze von 32 Byte beginnen. Andere Strukturtypen, die mit diesem Typ als Element deklariert sind, behalten das Ausrichtungsattribut dieses Typs bei. Das heißt, jede Struktur als Str1 Element verfügt über ein Ausrichtungsattribut von mindestens 32.

sizeof(struct Str1) Hier ist gleich 32. Wenn ein Array von Str1 Objekten erstellt wird und die Basis des Arrays 32-Byte ausgerichtet ist, wird jedes Element des Arrays ebenfalls 32 Byte ausgerichtet. Verwenden Sie die Verwendung _aligned_malloc, um ein Array zu erstellen, dessen Basis ordnungsgemäß im dynamischen Speicher ausgerichtet ist. Oder schreiben Sie Ihren eigenen Zuweisungsgeber.

Der sizeof-Wert für jede Struktur ist der Offset des letzten Members plus die Größe dieses Members, aufgerundet auf das nächste Vielfache des größten Memberausrichtungswerts oder den Ausrichtungswert der gesamten Struktur, je nachdem, welcher Wert größer ist.

Für die Strukturausrichtung verwendet der Compiler diese Regeln:

  • Sofern sie nicht mit __declspec(align(#)) überschrieben wird, ist die Ausrichtung eines skalaren Strukturmembers das Minimum seiner Größe und der aktuellen Verpackung.

  • Sofern sie nicht mit __declspec(align(#)) überschrieben wird, ist die Ausrichtung einer Struktur das Maximum der einzelnen Ausrichtungen ihrer Member.

  • Ein Strukturelement wird an einem Offset vom Anfang der übergeordneten Struktur platziert, das das kleinste Vielfache seiner Ausrichtung größer oder gleich dem Offset des Endes des vorherigen Elements ist.

  • Die Größe einer Struktur ist das kleinste Vielfache seiner Ausrichtung größer oder gleich dem Offset des Endes des letzten Members.

__declspec(align(#)) kann lediglich Ausrichtungseinschränkungen erhöhen.

Weitere Informationen finden Sie unter:

align Beispiele

Die folgenden Beispiele zeigen, wie sich __declspec(align(#)) auf die Größe und die Ausrichtung der Datenstrukturen auswirkt. Die Beispiele gehen von folgenden Definitionen aus:

#define CACHE_LINE  32
#define CACHE_ALIGN __declspec(align(CACHE_LINE))

In diesem Beispiel wird die S1-Struktur mit __declspec(align(32)) definiert. Alle Verwendungen von S1 für eine Variablendefinition oder andere Typdeklarationen sind mit 32 Bytes ausgerichtet. sizeof(struct S1) gibt 32 zurück, und S1 weist 16 Auffüll-Bytes auf, die den 16 Bytes folgen, die für die Aufnahme der vier ganzen Zahlen erforderlich sind. Jedes int Element erfordert eine 4-Byte-Ausrichtung, die Ausrichtung der Struktur selbst wird jedoch als 32 deklariert. Dann beträgt die Gesamtausrichtung 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

In diesem Beispiel gibt sizeof(struct S2) 16 zurück, was genau der Summe der Membergrößen entspricht, da es ein Vielfaches der größten Ausrichtungsanforderung (ein Vielfaches von 8) ist.

__declspec(align(8)) struct S2 {
   int a, b, c, d;
};

Im folgenden Beispiel gibt sizeof(struct S3) 64 zurück.

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

Beachten Sie in diesem Beispiel, dass a die Ausrichtung des natürlichen Typs, in diesem Fall 4 Bytes, aufweist. Allerdings muss S1 mit 32 Bytes ausgerichtet sein. Es folgen a28 Bytes Abstand, sodass s1 sie bei Offset 32 beginnen. S4 erbt dann die Ausrichtungsanforderung von S1, da es die größte Ausrichtungsanforderung in der Struktur ist. sizeof(struct S4) gibt 64 zurück.

struct S4 {
   int a;
   // 28 bytes padding
   struct S1 s1;      // S4 inherits cache alignment requirement of S1
};

Die folgenden drei Variablendeklarationen verwenden auch __declspec(align(#)). In jedem Fall muss die Variable mit 32 Bytes ausgerichtet sein. Im Array ist die Basisadresse des Arrays, nicht jedes Arrayelement, 32 Byte ausgerichtet. Der sizeof Wert für jedes Arrayelement ist nicht betroffen, wenn Sie es verwenden __declspec(align(#)).

CACHE_ALIGN int i;
CACHE_ALIGN int array[128];
CACHE_ALIGN struct s2 s;

Um jeden Member eines Arrays auszurichten, sollte Code wie dieser verwendet werden:

typedef CACHE_ALIGN struct { int a; } S5;
S5 array[10];

In diesem Beispiel sehen Sie, dass die Ausrichtung der Struktur selbst und die Ausrichtung des ersten Elements identisch sind:

CACHE_ALIGN struct S6 {
   int a;
   int b;
};

struct S7 {
   CACHE_ALIGN int a;
               int b;
};

S6 und S7 weisen identische Ausrichtungs-, Speicherbelegungs- und Größeneigenschaften auf.

In diesem Beispiel ist die Ausrichtung der Anfangsadressen von a, b, c, und d 4, 1, 4 und 1.

void fn() {
   int a;
   char b;
   long c;
   char d[10]
}

Wenn der Speicher für Heaps zugewiesen wird, hängt die Ausrichtung davon ab, welche Speicherbelegungsfunktion aufgerufen wird. Wenn Sie beispielsweise malloc verwenden, hängt das Ergebnis von der Größe des Operanden ab. Wenn arg>= 8, wird der zurückgegebene Speicher 8-Byte ausgerichtet. Wenn Arg< 8, ist die Ausrichtung des zurückgegebenen Speichers die erste Potenz von 2 kleiner als arg. Wenn Sie beispielsweise verwenden malloc(7), beträgt die Ausrichtung 4 Byte.

Definieren neuer Typen mit __declspec(align(#))

Sie können einen Typ mit einem Ausrichtungsmerkmal definieren.

Sie können z. B. einen struct Ausrichtungswert auf diese Weise definieren:

struct aType {int a; int b;};
typedef __declspec(align(32)) struct aType bType;

aType Jetzt und bType sind die gleiche Größe (8 Byte), aber Variablen vom Typ bType sind 32-Byte ausgerichtet.

Ausrichten von Daten im lokalen Threadspeicher

Statische lokale Threadspeicher (TLS), die mit dem __declspec(thread)-Attribut erstellt und im TLS-Abschnitt des Images platziert wurden, verhalten sich bei der Ausrichtung wie normale statische Daten. Zum Erstellen von TLS-Daten ordnet das Betriebssystem die Größe des TLS-Abschnitts zu und berücksichtigt das Ausrichtungsattribut für TLS-Abschnitte.

Dieses Beispiel zeigt verschiedene Möglichkeiten, ausgerichtete Daten in den threadlokalen Speicher zu platzieren.

// 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;

Funktionsweise align von Datenverpackungen

Die /Zp Compileroption und das pack Pragma wirken sich auf packende Daten für Struktur- und Vereinigungsmitglieder aus. In diesem Beispiel wird gezeigt, wie /Zp und __declspec(align(#)) zusammenarbeiten:

struct S {
   char a;
   short b;
   double c;
   CACHE_ALIGN double d;
   char e;
   double f;
};

In der folgenden Tabelle ist der Offset jedes Elements unter verschiedenen /Zp (oder #pragma pack) Werten aufgeführt, der zeigt, wie die beiden Elemente interagieren.

Variable /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

Weitere Informationen finden Sie unter /Zp (Strukturelementausrichtung).

Der Offset eines Objekts basiert auf dem Offset des vorherigen Objekts und der aktuellen Verpackungseinstellung, es sei denn, das Objekt weist ein __declspec(align(#))-Attribut auf. In diesem Fall basiert die Ausrichtung auf dem Offset des vorherigen Objekts und dem __declspec(align(#))-Wert für das Objekt.

Ende Microsoft-spezifisch

Siehe auch

__declspec
Übersicht über ARM-ABI-Konventionen
Softwarekonventionen bei x64-Systemen