align (C++)

Verwenden Sie in Visual Studio 2015 und höher den C++11-Standardauszeichneralignas, 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 Daten, die an 16-Byte-Grenzen ausgerichtet sind. Die Ausrichtung häufig verwendeter Daten an die Cachezeilengröße des Prozessors verbessert die Cacheleistung. Wenn Sie beispielsweise eine Struktur definieren, deren Größe kleiner als 32 Bytes ist, möchten Sie möglicherweise eine 32-Byte-Ausrichtung durchführen, 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 ist die Daten, die Sie als ausgerichtet deklarieren.

Informationen zum Zurückgeben eines Werts vom Typ, der die Ausrichtungsanforderung des Typs size_t ist, finden Sie unter alignof. Informationen zum Deklarieren nicht ausgerichteter Zeiger beim Ziel von 64-Bit-Prozessoren finden Sie unter __unaligned.

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

Der Compiler garantiert nicht, oder versucht, das Ausrichtungsattribute von Daten während eines Kopier- oder Datentransformationsvorgangs beizubehalten. Beispielsweise memcpy kann eine mit __declspec(align(#)) jedem Speicherort deklarierte Struktur kopiert werden. Gewöhnliche Allocatoren (z malloc. B. C++ operator newund Win32-Allocatoren) geben in der Regel Speicher zurück, die für __declspec(align(#)) Strukturen oder Arrays von Strukturen nicht ausreichend ausgerichtet sind. Um sicherzustellen, dass das Ziel eines Kopier- oder Datentransformationsvorgangs ordnungsgemäß ausgerichtet ist, verwenden Sie _aligned_malloc. Oder schreiben Sie Ihren eigenen Allocator.

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

Ohne __declspec(align(#)), richtet der Compiler normalerweise Daten auf natürlichen Grenzen basierend auf dem Zielprozessor und der Größe der Daten, bis zu 4-Byte-Grenzen auf 32-Bit-Prozessoren und 8-Byte-Grenzen auf 64-Bit-Prozessoren aus. Daten in Klassen oder Strukturen werden in der Klasse oder Struktur mindestens der natürlichen Ausrichtung und der aktuellen Packungseinstellung (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. Es bedeutet, dass alle statischen und automatischen Instanzen auf einer 32-Byte-Grenze beginnen. Andere Strukturtypen, die mit diesem Typ deklariert sind, erhalten das Ausrichtungsattribute dieses Typs. Das heißt, jede Struktur mit Str1 einem Element verfügt über ein Ausrichtungsattribute von mindestens 32.

sizeof(struct Str1) Hier ist gleich 32. Es bedeutet, dass ein Array von Str1 Objekten erstellt wird, und die Basis des Arrays 32-Byte ausgerichtet ist, ist jedes Element des Arrays auch 32-Byte ausgerichtet. Um ein Array zu erstellen, dessen Basis ordnungsgemäß im dynamischen Speicher ausgerichtet ist, verwenden Sie _aligned_malloc. Oder schreiben Sie Ihren eigenen Allocator.

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 am Anfang seiner übergeordneten Struktur platziert, die das kleinste Vielfache seiner Ausrichtung größer oder gleich dem Offset 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, aber die Ausrichtung der Struktur selbst wird als 32 deklariert. Dann ist 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. 28 Bytes des Abstands folgen a, damit s1 der Offset 32 beginnt. S4 Erbt dann die Ausrichtungsanforderung von S1, da es sich um die größte Ausrichtungsanforderung in der Struktur befindet. 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 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 sind die Ausrichtung der Startadressen von a, bc, und d sind 4, 1, 4 und 1, bzw. 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, ist der zurückgegebene Speicher 8-Byte ausgerichtet. Wenn arg< 8, ist die Ausrichtung des zurückgegebenen Speichers die erste Leistung von 2 kleiner als arg. Wenn Sie beispielsweise verwenden malloc(7), ist die Ausrichtung 4 Bytes.

Definieren neuer Typen mit __declspec(align(#))

Sie können einen Typ mit einem Ausrichtungsmerkmal definieren.

Sie können beispielsweise 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 Bytes), aber Variablen des Typs 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 Datenpackungen

Die /Zp Compileroption und das pack Pragma haben die Wirkung von Packdaten für Struktur- und Unionmitglieder. 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 wird der Offset jedes Members unter verschiedenen /Zp (oder #pragma pack) Werten aufgeführt, die zeigen, wie die beiden interagieren.

Variable /Zp1 /Zp2 /Zp4 /Zp8
a 0 0 0 0
b 1 2 2 2
c 3 4 4 8
T 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 (Struct Member Alignment).

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