align (C++)

Dans Visual Studio 2015 et versions ultérieures, utilisez alignas le spécificateur (C++11) pour contrôler l’alignement. Pour plus d’informations, consultez Alignement.

Section spécifique à Microsoft

Utilisez __declspec(align(#)) pour contrôler avec précision l'alignement des données définies par l'utilisateur (par exemple, les allocations statiques ou les données automatiques dans une fonction).

Syntaxe

__declspec( align(#) )déclarateur

Notes

L'écriture d'applications qui utilisent les dernières instructions du processeur introduit de nouvelles contraintes et de nouveaux problèmes. De nombreuses nouvelles instructions nécessitent que les données soient alignées sur les limites de 16 octets. L’alignement des données fréquemment utilisées sur la taille de ligne de cache du processeur améliore les performances du cache. Par exemple, si vous définissez une structure dont la taille est inférieure à 32 octets, vous souhaiterez peut-être un alignement de 32 octets pour vous assurer que les objets de ce type de structure sont efficacement mis en cache.

# est la valeur d’alignement. Les entrées valides sont des puissances entières de deux comprises entre 1 et 8192 (octets), telles que 2, 4, 8, 16, 32 ou 64. declarator est les données que vous déclarez comme alignées.

Pour plus d’informations sur la façon de retourner une valeur de type size_t qui est l’exigence d’alignement du type, consultez alignof. Pour plus d’informations sur la déclaration de pointeurs non alignés lors du ciblage de processeurs 64 bits, consultez __unaligned.

Vous pouvez utiliser __declspec(align(#)) lorsque vous définissez un struct, unionou classquand vous déclarez une variable.

Le compilateur ne garantit pas ou tente de conserver l’attribut d’alignement des données pendant une opération de copie ou de transformation de données. Par exemple, memcpy peut copier un struct déclaré avec __declspec(align(#)) n’importe quel emplacement. Les allocateurs ordinaires (par exemple, mallocC++ operator newet les allocateurs Win32) retournent généralement la mémoire qui n’est pas alignée pour __declspec(align(#)) les structures ou les tableaux de structures. Pour garantir que la destination d’une opération de copie ou de transformation de données est correctement alignée, utilisez _aligned_malloc. Ou écrivez votre propre allocateur.

Vous ne pouvez pas spécifier d’alignement pour les paramètres de fonction. Lorsque vous transmettez des données qui ont un attribut d’alignement par valeur sur la pile, la convention appelante contrôle son alignement. Si l'alignement des données est important dans la fonction appelée, copiez le paramètre dans la mémoire correctement alignée avant de l'utiliser.

Sans __declspec(align(#)), le compilateur aligne généralement les données sur les limites naturelles en fonction du processeur cible et de la taille des données, jusqu’à 4 octets limites sur les processeurs 32 bits et les limites de 8 octets sur les processeurs 64 bits. Les données des classes ou des structures sont alignées dans la classe ou la structure au minimum de son alignement naturel et du paramètre d’emballage actuel (à partir ou à partir de #pragma pack l’option du /Zp compilateur).

Cet exemple illustre l'utilisation de __declspec(align(#)) :

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

Ce type a maintenant un attribut d'alignement de 32 octets. Cela signifie que toutes les instances statiques et automatiques démarrent sur une limite de 32 octets. D’autres types de structure déclarés avec ce type en tant que membre conservent l’attribut d’alignement de ce type. Autrement dit, toute structure avec Str1 comme élément a un attribut d’alignement d’au moins 32.

Ici, sizeof(struct Str1) est égal à 32. Cela implique que si un tableau d’objets Str1 est créé et que la base du tableau est alignée sur 32 octets, chaque membre du tableau est également aligné sur 32 octets. Pour créer un tableau dont la base est correctement alignée dans la mémoire dynamique, utilisez _aligned_malloc. Ou écrivez votre propre allocateur.

La valeur sizeof d'une structure quelconque est le décalage du membre final, plus la taille de ce membre, arrondie au multiple le plus proche de la plus grande valeur membre d'alignement du membre ou de la valeur d'alignement de la structure entière, quelle que soit la valeur la plus grande.

Le compilateur utilise ces règles pour l'alignement de la structure :

  • À moins d'une substitution par __declspec(align(#)), l'alignement d'un membre de structure scalaire représente le minimum de sa taille et de la compression actuelle.

  • À moins d'une substitution par __declspec(align(#)), l'alignement d'une structure est la valeur maximale des alignements de ses membres.

  • Un membre de structure est placé à un décalage du début de sa structure parente qui est le plus petit multiple de son alignement supérieur ou égal au décalage de la fin du membre précédent.

  • La taille d'une structure est le plus petit multiple de son plus grand alignement supérieur ou égal au décalage de la fin de son dernier membre.

__declspec(align(#)) peut uniquement augmenter les restrictions d'alignement.

Pour plus d’informations, consultez l’article suivant :

align Exemples

Les exemples suivants montrent comment __declspec(align(#)) affecte la taille et l'alignement des structures de données. Les exemples supposent les définitions suivantes :

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

Dans cet exemple, la structure S1 est définie à l'aide de __declspec(align(32)). Toutes les utilisations de S1 pour une définition de variable ou dans d'autres types de déclaration sont alignées sur 32 octets. sizeof(struct S1) retourne 32, et S1 a 16 octets de remplissage après les 16 octets requis pour contenir les quatre entiers. Chaque int membre nécessite un alignement de 4 octets, mais l’alignement de la structure elle-même est déclaré comme étant 32. L’alignement global est alors 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

Dans cet exemple, sizeof(struct S2) retourne 16, qui est exactement la somme des tailles membres, car il s’agit d’un multiple de la plus grande exigence d’alignement (un multiple de 8).

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

Dans l'exemple suivant, sizeof(struct S3) retourne 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
};

Dans cet exemple, notez que a a l'alignement de son type naturel, dans le cas présent, 4 octets. Toutefois, S1 doit être aligné sur 32 octets. 28 octets de remplissage suivent a, ce qui s1 commence au décalage 32. S4 hérite ensuite de l’exigence d’alignement, S1car il s’agit de la plus grande exigence d’alignement dans la structure. sizeof(struct S4) retourne 64.

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

Les trois déclarations de variable suivantes utilisent également __declspec(align(#)). Dans chaque cas, la variable doit être alignée sur 32 octets. Dans le tableau, l’adresse de base du tableau, et non chaque membre du tableau, est alignée sur 32 octets. La sizeof valeur de chaque membre de tableau n’est pas affectée lorsque vous utilisez __declspec(align(#)).

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

Pour aligner chaque membre d'un tableau, écrivez un code tel que le suivant :

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

Dans cet exemple, notez que l'alignement de la structure elle-même et l'alignement du premier élément ont le même effet :

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

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

S6 et S7 ont les mêmes caractéristiques d'alignement, d'allocation et de taille.

Dans cet exemple, l’alignement des adresses de départ de a, b, cet d sont respectivement 4, 1, 4 et 1.

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

Quand la mémoire est allouée sur le tas, l'alignement dépend de la fonction d'allocation appelée. Par exemple, si vous utilisez malloc, le résultat dépend de la taille d’opérande. Si arg>= 8, la mémoire retournée est alignée sur 8 octets. Si arg< 8, l’alignement de la mémoire retournée est la première puissance de 2 inférieure à arg. Par exemple, si vous utilisez malloc(7), l’alignement est de 4 octets.

Définition de nouveaux types avec __declspec(align(#))

Vous pouvez définir un type avec une caractéristique d'alignement.

Par exemple, vous pouvez définir une struct valeur d’alignement de cette façon :

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

À présent, aType et bType sont de la même taille (8 octets), mais les variables de type bType sont alignées sur 32 octets.

Alignement des données dans le stockage local de thread

Le stockage local des threads de type statique (TLS) créé avec l'attribut __declspec(thread) et placé dans la section TLS de l'image contribue à l'alignement exactement comme les données statiques normales. Pour créer des données TLS, le système d'exploitation alloue de la mémoire de la taille de la section TLS et respecte l'attribut d'alignement de la section TLS.

Cet exemple montre différentes façons de placer des données alignées dans le stockage local des threads.

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

Fonctionnement align de l’empaquetage des données

L’option /Zp du compilateur et le pack pragma ont l’effet d’empaqueter des données pour les membres de la structure et de l’union. Cet exemple montre comment /Zp et __declspec(align(#)) travailler ensemble :

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

Le tableau suivant répertorie le décalage de chaque membre sous des valeurs (ou#pragma pack) différentes /Zp , montrant comment les deux interagissent.

Variable /Zp1 /Zp2 /Zp4 /Zp8
a 0 0 0 0
b 1 2 2 2
c 3 4 4 8
j 32 32 32 32
e 40 40 40 40
f 41 42 44 48
sizeof(S) 64 64 64 64

Pour plus d’informations, consultez /Zp (Alignement des membres de struct).

Le décalage d'un objet est basé sur le décalage de l'objet précédent et du paramètre de compactage actif, sauf si l'objet a un attribut __declspec(align(#)). Dans ce cas, l'alignement est basé sur le décalage de l'objet précédent et de la valeur __declspec(align(#)) pour l'objet.

FIN de la section spécifique à Microsoft

Voir aussi

__declspec
Vue d’ensemble des conventions ABI ARM
Conventions des logiciels x64