align (C++)

In Visual Studio 2015 e versioni successive usare alignas l'identificatore (C++11) per controllare l'allineamento. Per altre informazioni, vedere Allineamento.

Sezione specifica Microsoft

Usare __declspec(align(#)) per controllare con precisione l'allineamento dei dati definiti dall'utente (ad esempio, le allocazioni statiche o i dati automatici di una funzione).

Sintassi

__declspec( align(#) )declarator

Osservazioni:

La scrittura di applicazioni che usano le più recenti istruzioni del processore porta alla luce nuovi vincoli e problemi. Molte nuove istruzioni richiedono che i dati siano allineati ai limiti di 16 byte. L'allineamento dei dati usati di frequente alle dimensioni della riga della cache del processore migliora le prestazioni della cache. Ad esempio, se si definisce una struttura la cui dimensione è inferiore a 32 byte, è possibile che si voglia un allineamento a 32 byte per assicurarsi che gli oggetti del tipo di struttura siano memorizzati nella cache in modo efficiente.

# è il valore di allineamento. Le voci valide sono numeri interi potenze di 2, da 1 a 8192 (byte), ad esempio 2, 4, 8, 16, 32 o 64. declarator è i dati dichiarati come allineati.

Per informazioni su come restituire un valore di tipo size_t che rappresenta il requisito di allineamento del tipo, vedere alignof. Per informazioni su come dichiarare puntatori non idonei quando si punta a processori a 64 bit, vedere __unaligned.

È possibile usare __declspec(align(#)) quando si definisce un structoggetto , uniono classo quando si dichiara una variabile.

Il compilatore non garantisce o tenta di mantenere l'attributo di allineamento dei dati durante un'operazione di copia o trasformazione dei dati. Ad esempio, memcpy può copiare uno struct dichiarato con in __declspec(align(#)) qualsiasi posizione. Gli allocatori ordinari (ad esempio, malloc, C++ operator newe gli allocatori Win32) restituiscono in genere memoria non allineata per __declspec(align(#)) strutture o matrici di strutture. Per garantire che la destinazione di un'operazione di copia o trasformazione dati sia allineata correttamente, usare _aligned_malloc. In alternativa, scrivere il proprio allocatore.

Non è possibile specificare l'allineamento per i parametri della funzione. Quando si passano dati con un attributo di allineamento per valore nello stack, la convenzione di chiamata ne controlla l'allineamento. Se l'allineamento dei dati è importante nella funzione chiamata, copiare il parametro nella memoria correttamente allineata prima dell'uso.

Senza __declspec(align(#)), il compilatore allinea in genere i dati ai limiti naturali in base al processore di destinazione e alle dimensioni dei dati, fino a limiti di 4 byte su processori a 32 bit e limiti a 8 byte su processori a 64 bit. I dati nelle classi o nelle strutture sono allineati nella classe o nella struttura al minimo dell'allineamento naturale e dell'impostazione di compressione corrente (da #pragma pack o l'opzione del /Zp compilatore).

L'esempio seguente illustra l'uso di __declspec(align(#)):

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

Questo tipo ha ora un attributo di allineamento a 32 byte, Significa che tutte le istanze statiche e automatiche iniziano su un limite di 32 byte. Altri tipi di struttura dichiarati con questo tipo come membro mantengono l'attributo di allineamento di questo tipo. Ovvero, qualsiasi struttura con Str1 come elemento ha un attributo di allineamento di almeno 32.

In questo caso, sizeof(struct Str1) è uguale a 32. Implica che se viene creata una matrice di Str1 oggetti e la base della matrice è allineata a 32 byte, anche ogni membro della matrice è allineato a 32 byte. Per creare una matrice la cui base è allineata correttamente nella memoria dinamica, usare _aligned_malloc. In alternativa, scrivere il proprio allocatore.

Il valore di sizeof per tutte le strutture corrisponde all'offset del membro finale più la dimensione dello stesso membro, arrotondata al multiplo più vicino del valore di allineamento del membro più grande o del valore di allineamento dell'intera struttura, a seconda di quale sia il valore più grande.

Il compilatore usa le seguenti regole per l'allineamento della struttura:

  • A meno che non venga sottoposto a override con __declspec(align(#)), l'allineamento di un membro di struttura scalare corrisponde al valore minimo della propria dimensione e della compressione corrente.

  • A meno che non venga sottoposto a override con __declspec(align(#)), l'allineamento di una struttura corrisponde al valore massimo dell'allineamento dei propri membri.

  • Un membro della struttura viene posizionato in corrispondenza di un offset dall'inizio della struttura padre, ovvero il multiplo più piccolo dell'allineamento maggiore o uguale all'offset della fine del membro precedente.

  • La dimensione di una struttura corrisponde al multiplo più piccolo dell'allineamento maggiore o uguale all'offset della fine dell'ultimo membro presente.

__declspec(align(#)) può solo aumentare le restrizioni di allineamento.

Per altre informazioni, vedi:

align Esempi

Negli esempi seguenti viene illustrato come __declspec(align(#)) influisce sulla dimensione e sull'allineamento delle strutture di dati. Negli esempi si presuppongono le seguenti definizioni:

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

Nell'esempio seguente, la struttura S1 viene definita con __declspec(align(32)). Tutti gli usi di S1 per una definizione di variabile o in altre dichiarazioni dei tipi sono allineati a 32 byte. sizeof(struct S1) restituisce 32 e S1 ha 16 byte di riempimento, coerentemente alla necessità di avere 16 byte per contenere i quattro Integer. Ogni int membro richiede l'allineamento a 4 byte, ma l'allineamento della struttura stessa viene dichiarato come 32. Quindi l'allineamento complessivo è 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

Nell'esempio seguente, sizeof(struct S2) restituisce 16, che corrisponde alla somma delle dimensioni del membro, visto che tale valore è un multiplo del requisito di allineamento maggiore (un multiplo di 8).

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

Nell'esempio seguente, sizeof(struct S3) restituisce 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
};

Nell'esempio seguente, si noti che a ha l'allineamento del tipo naturale, in questo caso, a 4 byte. S1, però, deve essere allineato a 32 byte. 28 byte di riempimento seguono a, in modo che s1 inizi all'offset 32. S4 eredita quindi il requisito di allineamento di , perché è il requisito di S1allineamento più grande nella struttura. sizeof(struct S4) restituisce 64.

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

Le seguenti tre dichiarazioni di variabile usano anche __declspec(align(#)). In ogni caso, la variabile deve essere allineata a 32 byte. Nella matrice l'indirizzo di base della matrice, non ogni membro della matrice, è allineato a 32 byte. Il sizeof valore per ogni membro della matrice non è interessato quando si usa __declspec(align(#)).

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

Per allineare ogni membro di una matrice, è necessario usare un codice simile a quello indicato di seguito:

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

Nell'esempio seguente, si noti che l'allineamento della struttura e l'allineamento del primo elemento hanno lo stesso effetto:

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

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

S6 e S7 dispongono delle stesse caratteristiche di allineamento, allocazione e dimensione.

In questo esempio, l'allineamento degli indirizzi iniziali di a, b, ce d sono rispettivamente 4, 1, 4 e 1.

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

Se la memoria viene allocata nell'heap, l'allineamento dipende dalla funzione di allocazione che viene chiamata. Ad esempio, se si usa malloc, il risultato dipende dalla dimensione dell'operando. Se arg>= 8, la memoria restituita è allineata a 8 byte. Se arg< 8, l'allineamento della memoria restituita è la prima potenza di 2 minore di arg. Ad esempio, se si usa malloc(7), l'allineamento è di 4 byte.

Definizione di nuovi tipi con __declspec(align(#))

È possibile definire un tipo con una caratteristica di allineamento.

Ad esempio, è possibile definire un struct oggetto con un valore di allineamento in questo modo:

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

aType Ora e bType hanno le stesse dimensioni (8 byte), ma le variabili di tipo bType sono allineate a 32 byte.

Allineamento dei dati nell'archiviazione locale del thread

L'archiviazione locale di thread (TLS, Thread-Local Storage) statici creata con l'attributo __declspec(thread) e inserita nella sezione TLS dell'immagine funziona per l'allineamento esattamente come i dati statici normali. Per creare dati TLS, il sistema operativo alloca memoria con la stessa dimensione della sezione TLS e rispetta l'attributo di allineamento della sezione TLS.

L'esempio seguente illustra vari modi per inserire i dati allineati nell'archiviazione locale dei thread.

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

Come align funziona con la compressione dei dati

L'opzione /Zp del compilatore e il pack pragma hanno l'effetto della compressione dei dati per i membri della struttura e dell'unione. Questo esempio mostra come /Zp e __declspec(align(#)) lavorare insieme:

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

Nella tabella seguente viene elencato l'offset di ogni membro con valori diversi /Zp (o #pragma pack) che illustrano l'interazione tra i due membri.

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

Per altre informazioni, vedere (Allineamento membri struct).For more information, see /Zp (Struct Member Alignment).

L'offset di un oggetto è basato sull'offset tra l'oggetto precedente e l'impostazione di compressione corrente, a meno che l'oggetto non abbia un attributo __declspec(align(#)). In quest'ultimo caso, l'allineamento è basato sull'offset tra l'oggetto precedente e il valore __declspec(align(#)) dell'oggetto.

Fine sezione specifica Microsoft

Vedi anche

__declspec
Panoramica delle convenzioni ABI ARM
Convenzioni del software x64