Freigeben über


Ausrichtung

Eines der Features von C++ auf niedriger Ebene ist die Möglichkeit zum Angeben der präzisen Ausrichtung von Objekten im Speiche, um eine bestimmte Hardwarearchitektur optimal zu nutzen. Standardmäßig richtet der Compiler Klassen- und Strukturmber an seinen Größenwerten aus: bool und char auf 1-Byte-Begrenzungen, short auf 2-Byte-Begrenzungen, int, longund float auf 4-Byte-Begrenzungen und , doubleund , und long longlong double auf 8-Byte-Begrenzungen.

In den meisten Szenarien müssen Sie sich nie mit der Ausrichtung befassen, da die Standardausrichtung bereits optimal ist. In einigen Fällen können Sie jedoch erhebliche Leistungsverbesserungen oder Speichereinsparungen erzielen, indem Sie eine benutzerdefinierte Ausrichtung für Ihre Datenstrukturen angeben. Vor Visual Studio 2015 können Sie die microsoftspezifischen Schlüsselwort (keyword) __alignof verwenden und __declspec(align) eine Ausrichtung angeben, die größer als die Standardeinstellung ist. Ab Visual Studio 2015 sollten Sie die C++11-Standard-Schlüsselwort (keyword) und alignofalignas die maximale Codeübertragbarkeit verwenden. Die neuen Schlüsselwort (keyword) verhalten sich auf die gleiche Weise wie die microsoftspezifischen Erweiterungen. Die Dokumentation für diese Erweiterungen gilt auch für die neuen Schlüsselwort (keyword). Weitere Informationen finden Sie unter alignof Operator, alignas Bezeichner und Ausrichten. Der C++-Standard gibt kein Verpackungsverhalten für die Ausrichtung auf Begrenzungen an, die kleiner als der Compilerstandard für die Zielplattform sind. Daher müssen Sie microsoft #pragma pack in diesem Fall weiterhin verwenden.

Verwenden Sie die aligned_storage Klasse für die Speicherzuordnung von Datenstrukturen mit benutzerdefinierten Ausrichtungen. Die aligned_union Klasse dient zum Angeben der Ausrichtung für Gewerkschaften mit nichttriviellen Konstruktoren oder Destruktoren.

Ausrichtungs- und Speicheradressen

Die Ausrichtung ist eine Eigenschaft einer Speicheradresse, ausgedrückt als numerisches Adressmodulo der Potenz 2. Beispielsweise ist die Adresse 0x0001103F Modulo 4 3. Diese Adresse soll an 4n+3 ausgerichtet werden, wobei 4 die gewählte Potenz von 2 angibt. Die Ausrichtung einer Adresse hängt von der gewählten Potenz von 2 ab. Das gleiche Adressmodulo 8 ist 7. Eine Adresse wird als an X ausgerichtet betrachtet, wenn die Ausrichtung Xn+ 0 ist.

CPUs führen Anweisungen aus, die mit daten arbeiten, die im Arbeitsspeicher gespeichert sind. Die Daten werden durch ihre Adressen im Arbeitsspeicher identifiziert. Ein einzelnes Datum hat auch eine Größe. Ein Datum wird natürlich ausgerichtet , wenn seine Adresse an seine Größe ausgerichtet ist. Andernfalls wird sie falsch ausgerichtet . Beispielsweise wird ein Gleitkomma-Datum mit 8 Byte natürlich ausgerichtet, wenn die Adresse, mit der sie identifiziert wird, eine 8-Byte-Ausrichtung aufweist.

Compilerverarbeitung der Datenausrichtung

Compiler versuchen, Datenzuordnungen auf eine Weise vorzunehmen, die eine Fehlausrichtung von Daten verhindert.

Der Compiler weist für einfache Datentypen Adressen zu, die ein Vielfaches der Größe in Bytes des Datentyps entsprechen. Beispielsweise weist der Compiler Variablen des Typs long Adressen zu, die Vielfache von 4 sind, wobei die untersten 2 Bits der Adresse auf Null festgelegt werden.

Der Compiler sorgt auch dafür, dass strukturen so ausgerichtet werden, dass jedes Element der Struktur natürlich ausgerichtet wird. Betrachten Sie die Struktur struct x_ im folgenden Codebeispiel:

struct x_
{
   char a;     // 1 byte
   int b;      // 4 bytes
   short c;    // 2 bytes
   char d;     // 1 byte
} bar[3];

Der Compiler füllt die Struktur, um die natürliche Ausrichtung zu erzwingen.

Das folgende Codebeispiel zeigt, wie der Compiler die aufgefüllte Struktur im Arbeitsspeicher platziert:

// Shows the actual memory layout
struct x_
{
   char a;            // 1 byte
   char _pad0[3];     // padding to put 'b' on 4-byte boundary
   int b;            // 4 bytes
   short c;          // 2 bytes
   char d;           // 1 byte
   char _pad1[1];    // padding to make sizeof(x_) multiple of 4
} bar[3];

Beide Deklarationen werden als 12 Byte zurückgegeben sizeof(struct x_) .

Die zweite Deklaration enthält zwei Auffüllelemente:

  1. char _pad0[3] um das int b Element an einer Grenze von 4 Byte auszurichten.
  2. char _pad1[1] um die Arrayelemente der Struktur struct _x bar[3]; an einer Grenze von 4 Byte auszurichten.

Der Abstand richtet die Elemente bar[3] auf eine Weise aus, die den natürlichen Zugriff ermöglicht.

Das folgende Codebeispiel zeigt das bar[3] Arraylayout:

adr offset   element
------   -------
0x0000   char a;         // bar[0]
0x0001   char pad0[3];
0x0004   int b;
0x0008   short c;
0x000a   char d;
0x000b   char _pad1[1];

0x000c   char a;         // bar[1]
0x000d   char _pad0[3];
0x0010   int b;
0x0014   short c;
0x0016   char d;
0x0017   char _pad1[1];

0x0018   char a;         // bar[2]
0x0019   char _pad0[3];
0x001c   int b;
0x0020   short c;
0x0022   char d;
0x0023   char _pad1[1];

alignof und alignas

Der alignas Bezeichner ist eine tragbare, C++-Standardmethode zum Angeben der benutzerdefinierten Ausrichtung von Variablen und benutzerdefinierten Typen. Der alignof Operator ist ebenfalls eine standardmäßige, portierbare Methode zum Abrufen der Ausrichtung eines angegebenen Typs oder einer Variablen.

Beispiel

Sie können für eine Klasse, Struktur oder Vereinigung oder für einzelne Mitglieder verwenden alignas . Wenn mehrere alignas Bezeichner gefunden werden, wählt der Compiler den Wert mit dem größten Wert aus.

// alignas_alignof.cpp
// compile with: cl /EHsc alignas_alignof.cpp
#include <iostream>

struct alignas(16) Bar
{
    int i;       // 4 bytes
    int n;      // 4 bytes
    alignas(4) char arr[3];
    short s;          // 2 bytes
};

int main()
{
    std::cout << alignof(Bar) << std::endl; // output: 16
}

Siehe auch

Ausrichtung der Datenstruktur