align (C++)

En Visual Studio 2015 y versiones posteriores, use alignas el especificador (C++11) para controlar la alineación. Para obtener más información, consulte Alineación.

Específicos de Microsoft

Use __declspec(align(#)) para controlar con precisión la alineación de datos definidos por el usuario (por ejemplo, asignaciones estáticas o datos automáticos en una función).

Sintaxis

__declspec( align(#) )declarator

Comentarios

Las aplicaciones de escritura que utilizan las últimas instrucciones de procesador presentan nuevas restricciones y problemas. Muchas instrucciones nuevas requieren que los datos se alineen con límites de 16 bytes. La alineación de datos usados con frecuencia con el tamaño de línea de caché del procesador mejora el rendimiento de la memoria caché. Por ejemplo, si define una estructura cuyo tamaño es inferior a 32 bytes, es posible que desee una alineación de 32 bytes para asegurarse de que los objetos de ese tipo de estructura se almacenan en caché de forma eficaz.

# es el valor de alineación. Las entradas válidas son potencias enteras de dos desde 1 hasta 8192 (bytes), como 2, 4, 8, 16, 32 o 64. declarator corresponde a los datos que se declaran como alineados.

Para obtener información sobre cómo devolver un valor de tipo size_t, que es el requisito de alineación del tipo, consulte alignof. Para obtener información sobre cómo declarar punteros sin alinear cuando el destino son procesadores de 64 bits, consulte __unaligned.

Puede usar __declspec(align(#)) al definir struct, union, o class al declarar una variable.

El compilador no garantiza ni intenta conservar el atributo de alineación de los datos durante una operación de copia o transformación de datos. Por ejemplo, memcpy puede copiar una estructura declarada con __declspec(align(#)) a cualquier ubicación. Los asignadores normales (por ejemplo, malloc, C++ operator newy los asignadores Win32) normalmente devuelven memoria que no está alineada para __declspec(align(#)) estructuras o matrices de estructuras. Para garantizar que el destino de una operación de transformación de datos o copia está correctamente alineado, use _aligned_malloc. O bien, escriba su propio asignador.

No se puede especificar la alineación de los parámetros de la función. Cuando se pasan datos que tienen un atributo de alineación por valor en la pila, la convención de llamada controla su alineación. Si la alineación de los datos es importante en la función llamada, copie el parámetro en la memoria alineada correctamente antes de su uso.

Sin __declspec(align(#)), el compilador suele alinear los datos en los límites naturales basándose en el procesador de destino y el tamaño de los datos, hasta límites de 4 bytes en procesadores de 32 bits y límites de 8 bytes en procesadores de 64 bits. Los datos en clases o estructuras se alinean dentro de la clase o la estructura en el nivel mínimo de su alineación natural y el valor actual de empaquetado (desde #pragma pack o la opción /Zp del compilador).

Este ejemplo muestra el uso de __declspec(align(#)):

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

Ahora, este tipo tiene un atributo de alineación de 32 bytes. Esto significa que todas las instancias estáticas y automáticas empiezan en un límite de 32 bytes. Otros tipos de estructura declarados con este tipo como miembro conservan el atributo de alineación de este tipo. Es decir, cualquier estructura con Str1 como elemento tiene un atributo de alineación de al menos 32.

Aquí, sizeof(struct Str1) es igual a 32. Esto implica que si se crea una matriz de objetos Str1, y la base de la matriz tiene una alineación de 32 bytes, cada miembro de la matriz tiene también una alineación de 32 bytes. Para crear una matriz cuya base esté alineada correctamente en la memoria dinámica, use _aligned_malloc. O bien, escriba su propio asignador.

El valor sizeof para cualquier estructura es el desplazamiento del miembro final, más el tamaño de ese miembro, redondeado al múltiplo más próximo del mayor valor de alineación de los miembros o del valor total de alineación de estructura, el que sea mayor.

El compilador utiliza estas reglas para la alineación de la estructura:

  • A menos que se reemplace con __declspec(align(#)), la alineación de un miembro de estructura escalar es el mínimo de su tamaño y empaquetado actual.

  • A menos que se reemplace con __declspec(align(#)), la alineación de una estructura es el máximo de las alineaciones individuales de sus miembros.

  • Un miembro de estructura se coloca en un desplazamiento desde el inicio de su estructura primaria que es el múltiplo más pequeño de su alineación mayor o igual que el desplazamiento del final del miembro anterior.

  • El tamaño de una estructura es el múltiplo más pequeño de su alineación, que es mayor o igual que el desplazamiento del final de su último miembro.

__declspec(align(#)) solo puede aumentar restricciones de alineación.

Para más información, vea:

align Ejemplos

En los ejemplos siguientes se muestra cómo __declspec(align(#)) afecta al tamaño y la alineación de estructuras de datos. En los ejemplos se suponen las definiciones siguientes:

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

En este ejemplo, la S1 estructura se define mediante el uso de __declspec(align(32)). Todos los usos de S1 para una definición de variable o en otro tipo de declaraciones tienen una alineación de 32 bytes. sizeof(struct S1) devuelve 32 y S1 tiene 16 bytes de relleno a continuación de los 16 bytes necesarios para contener los cuatro enteros. Cada miembro int requiere una alineación de 4 bytes, pero la alineación de la propia estructura se declara de 32. Por lo tanto, la alineación total es 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

En este ejemplo, sizeof(struct S2) devuelve 16, que es exactamente la suma de los tamaños de miembro, porque es un múltiplo del mayor requisito de alineación (un múltiplo de 8).

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

En el ejemplo siguiente, sizeof(struct S3) devuelve 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
};

En este ejemplo, observe que a tiene la alineación de su tipo natural, en este caso, 4 bytes. Sin embargo, S1 debe tener una alineación de 32 bytes. 28 bytes de relleno siguen a a, de modo que s1 empieza en la posición de desplazamiento 32. S4 hereda después el requisito de alineación de S1, porque es el requisito de alineación mayor de la estructura. sizeof(struct S4) devuelve 64.

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

Las tres declaraciones de variable siguientes también utilizan __declspec(align(#)). En cada caso, la variable debe tener una alineación de 32 bytes. En la matriz, la dirección base de la matriz, no cada miembro de la matriz, tiene una alineación de 32 bytes. El valor sizeof para cada miembro de la matriz no se ve afectado por el uso de __declspec(align(#)).

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

Para alinear cada miembro de una matriz, se debe utilizar código como el siguiente:

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

En este ejemplo, observe que la alineación de la propia estructura y la alineación del primer elemento tienen el mismo efecto:

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

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

S6 y S7 tienen características de alineación, asignación y tamaño idénticas.

En este ejemplo, la alineación de las direcciones iniciales de a, b, c y d son 4, 1, 4 y 1, respectivamente.

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

La alineación cuando la memoria se asignó en el montón depende de qué función de asignación se invoque. Por ejemplo, si utiliza malloc, el resultado depende del tamaño de operando. Si arg>= 8, la memoria devuelta tiene una alineación de 8 bytes. Si arg< 8, la alineación de la memoria devuelta es la primera potencia de 2 menor que arg. Por ejemplo, si usa malloc(7), la alineación es de 4 bytes.

Definición de nuevos tipos con __declspec(align(#))

Puede definir un tipo con una característica de alineación.

Por ejemplo, puede definir un struct con un valor de alineación de la forma siguiente:

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

Ahora, aType y bType tienen el mismo tamaño (8 bytes) pero las variables de tipo bType tienen una alineación de 32 bytes.

Alinear datos en el almacenamiento local para el subproceso

El almacenamiento local de subprocesos estáticos (TLS) creado con el atributo __declspec(thread) y colocado en la sección de TLS en la imagen funciona para la alineación exactamente igual que los datos estáticos normales. Para crear datos TLS, el sistema operativo asigna a la memoria el tamaño de la sección de TLS y respetando el atributo de la alineación de la sección de TLS.

En este ejemplo se muestran diversas maneras de colocar datos alineados en el almacenamiento local para el subproceso.

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

Cómo align funciona con el empaquetado de datos

La opción del compilador /Zp y la pragma de pack tienen el efecto de empaquetar datos para los miembros de estructura y de unión. En este ejemplo se muestra cómo /Zp y __declspec(align(#)) trabajan juntos:

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

En la tabla siguiente se muestra el desplazamiento de cada miembro bajo diversos valores de /Zp (o #pragma pack), al mostrar cómo interactúan ambos.

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

Para obtener más información, consulte /Zp (Alineación de miembros de estructura).

El desplazamiento de un objeto se basa en el desplazamiento del objeto anterior y el valor actual de empaquetado, a menos que el objeto tenga un atributo __declspec(align(#)), en cuyo caso la alineación se basa en el desplazamiento del objeto anterior y el valor __declspec(align(#)) para el objeto.

FIN de Específicos de Microsoft

Consulte también

__declspec
Información general sobre las convenciones ABI de ARM
Convenciones de software x64