Share via


Allineamento

Una delle funzionalità di basso livello di C++ è costituita dalla possibilità di specificare l'allineamento preciso degli oggetti in memoria per sfruttare al massimo una specifica architettura hardware. Per impostazione predefinita, il compilatore allinea i membri di classe e struct sul valore delle dimensioni: bool e char sui limiti a 1 byte, short su limiti a 2 byte, int, longe float su limiti a 4 byte e , doublee long longlong double su limiti a 8 byte.

Nella maggior parte degli scenari, non è mai necessario preoccuparsi dell'allineamento perché l'allineamento predefinito è già ottimale. In alcuni casi, tuttavia, è possibile ottenere miglioramenti significativi delle prestazioni o risparmi di memoria specificando un allineamento personalizzato per le strutture di dati. Prima di Visual Studio 2015 è possibile usare le parole chiave __alignof specifiche di Microsoft e __declspec(align) specificare un allineamento maggiore del valore predefinito. A partire da Visual Studio 2015 è consigliabile usare le parole chiave alignof standard C++11 e alignas per ottenere la massima portabilità del codice. Le nuove parole chiave si comportano nello stesso modo delle estensioni specifiche di Microsoft. La documentazione per tali estensioni si applica anche alle nuove parole chiave. Per altre informazioni, vedere alignof Operatore, alignas identificatore e allineamento. Lo standard C++ non specifica il comportamento di compressione per l'allineamento sui limiti inferiori al valore predefinito del compilatore per la piattaforma di destinazione, quindi è comunque necessario usare Microsoft #pragma pack in questo caso.

Usare la classe aligned_storage per l'allocazione di memoria delle strutture di dati con allineamenti personalizzati. La classe aligned_union consente di specificare l'allineamento per le unioni con costruttori o distruttori nontriviali.

Allineamento e indirizzi di memoria

Per allineamento si intende una proprietà di un indirizzo di memoria, espresso come modulo di indirizzo numerico di una potenza di 2. Ad esempio, l'indirizzo 0x0001103F modulo 4 è 3. Questo indirizzo viene detto essere allineato a 4n+3, dove 4 indica la potenza scelta di 2. L'allineamento di un indirizzo dipende dalla potenza scelta di 2. Il modulo 8 dello stesso indirizzo è 7. Si dice che un indirizzo è allineato a X se il relativo allineamento è Xn+0.

Le CPU eseguono istruzioni che operano sui dati archiviati in memoria. I dati vengono identificati dagli indirizzi in memoria. Un singolo datum ha anche una dimensione. Viene chiamato un datum allineato naturalmente se l'indirizzo è allineato alle dimensioni. In caso contrario, viene chiamato non allineato . Ad esempio, un datum a virgola mobile a 8 byte viene allineato naturalmente se l'indirizzo usato per identificarlo ha un allineamento a 8 byte.

Gestione del compilatore dell'allineamento dei dati

I compilatori tentano di eseguire allocazioni di dati in modo da impedire il disallineamento dei dati.

Per i tipi di dati semplici il compilatore assegna indirizzi che sono multipli delle dimensioni in byte del tipo di dati. Ad esempio, il compilatore assegna indirizzi a variabili di tipo long multiple pari a 4, impostando i 2 bit inferiori dell'indirizzo su zero.

Il compilatore riempie anche le strutture in modo da allineare naturalmente ogni elemento della struttura. Si consideri la struttura struct x_ nell'esempio di codice seguente:

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

Il compilatore aggiunge elementi di spaziatura interna in questa struttura in modo applicare naturalmente l'allineamento.

Nell'esempio di codice seguente viene illustrato come il compilatore inserisce la struttura riempita in memoria:

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

Entrambe le dichiarazioni restituiscono sizeof(struct x_) 12 byte.

La seconda dichiarazione include due elementi di spaziatura interna:

  1. char _pad0[3] per allineare il int b membro su un limite di 4 byte.
  2. char _pad1[1] per allineare gli elementi della matrice della struttura struct _x bar[3]; su un limite a 4 byte.

La spaziatura interna allinea gli elementi di bar[3] in modo da consentire l'accesso naturale.

L'esempio di codice seguente illustra il layout della bar[3] matrice:

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 e alignas

L'identificatore alignas è un modo standard C++ portabile per specificare l'allineamento personalizzato di variabili e tipi definiti dall'utente. L'operatore alignof è analogamente un modo portabile e standard per ottenere l'allineamento di un tipo o di una variabile specificata.

Esempio

È possibile usare alignas in una classe, uno struct o un'unione o su singoli membri. Quando vengono rilevati più alignas identificatori, il compilatore sceglie quello con il valore più grande.

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

Vedi anche

Allineamento della struttura dei dati