Alignment
Une des fonctionnalités de bas niveau de C++ est la possibilité de spécifier avec précision l’alignement des objets en mémoire afin d’exploiter au mieux les capacités d’une architecture matérielle spécifique. Par défaut, le compilateur aligne les membres de classe et de struct sur leur valeur de taille : bool
et sur les limites de 1 octet, short
sur les limites de 2 octets, et long
float
int
sur les limites de 4 octets, et double
long double
long long
sur les limites de 8 octets.char
Dans la plupart des scénarios, vous n’avez jamais à vous soucier de l’alignement, car l’alignement par défaut est déjà optimal. Dans certains cas, toutefois, vous pouvez obtenir des améliorations significatives des performances ou des économies de mémoire en spécifiant un alignement personnalisé pour vos structures de données. Avant Visual Studio 2015, vous pouvez utiliser les mot clé __alignof
spécifiques à Microsoft et __declspec(align)
spécifier un alignement supérieur à la valeur par défaut. À compter de Visual Studio 2015, vous devez utiliser les mot clé alignof
standard C++11 et alignas
pour une portabilité maximale du code. Les nouvelles mot clé se comportent de la même façon que les extensions spécifiques à Microsoft. La documentation de ces extensions s’applique également aux nouvelles mot clé. Pour plus d’informations, consultez alignof
Opérateur, alignas
Spécificateur et alignement. La norme C++ ne spécifie pas le comportement d’emballage pour l’alignement sur les limites inférieures à la valeur par défaut du compilateur pour la plateforme cible. Vous devez donc toujours utiliser Microsoft #pragma pack
dans ce cas.
Utilisez la classe aligned_storage pour l’allocation de mémoire de structures de données avec des alignements personnalisés. La classe aligned_union est destinée à spécifier l’alignement pour les unions avec des constructeurs ou des destructeurs nontrivials.
Adresses d’alignement et de mémoire
L'alignement est une propriété d'une adresse mémoire, exprimée sous la forme de l'adresse numérique modulo une puissance de 2. Par exemple, l’adresse 0x0001103F modulo 4 est 3. Cette adresse est dite alignée sur 4n+3, où 4 indique la puissance choisie de 2. L’alignement d’une adresse dépend de la puissance choisie de 2. La même adresse modulo 8 est 7. Une adresse est considérée comme étant alignée sur X si son alignement est Xn+0.
Les processeurs exécutent des instructions qui fonctionnent sur les données stockées en mémoire. Les données sont identifiées par leurs adresses en mémoire. Une référence unique a également une taille. Nous appelons une référence naturellement alignée si son adresse est alignée sur sa taille. Elle est appelée mal alignée sinon. Par exemple, une référence à virgule flottante de 8 octets est naturellement alignée si l’adresse utilisée pour l’identifier a un alignement de 8 octets.
Gestion par le compilateur de l’alignement des données
Les compilateurs tentent d’effectuer des allocations de données d’une manière qui empêche l’alignement incorrect des données.
Pour les types de données simples, le compilateur assigne des adresses qui sont des multiples de la taille en octets du type de données. Par exemple, le compilateur affecte des adresses à des variables de type long
multiples de 4, en définissant les 2 bits inférieurs de l’adresse sur zéro.
Le compilateur place également les structures d’une manière qui aligne naturellement chaque élément de la structure. Considérez la structure struct x_
dans l’exemple de code suivant :
struct x_
{
char a; // 1 byte
int b; // 4 bytes
short c; // 2 bytes
char d; // 1 byte
} bar[3];
Le compilateur remplit cette structure pour appliquer naturellement l'alignement.
L’exemple de code suivant montre comment le compilateur place la structure rembourrée en mémoire :
// 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];
Les deux déclarations sont retournées sizeof(struct x_)
sous la forme de 12 octets.
La deuxième déclaration inclut deux éléments de remplissage :
char _pad0[3]
pour aligner leint b
membre sur une limite de 4 octets.char _pad1[1]
pour aligner les éléments de tableau de la structurestruct _x bar[3];
sur une limite de 4 octets.
Le remplissage aligne les éléments d’une bar[3]
manière qui permet un accès naturel.
L’exemple de code suivant montre la bar[3]
disposition du tableau :
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
et alignas
Le alignas
spécificateur est un moyen standard portable C++ de spécifier l’alignement personnalisé des variables et des types définis par l’utilisateur. L’opérateur alignof
est également un moyen standard et portable d’obtenir l’alignement d’un type ou d’une variable spécifié.
Exemple
Vous pouvez utiliser alignas
sur une classe, un struct ou une union, ou sur des membres individuels. Lorsque plusieurs alignas
spécificateurs sont rencontrés, le compilateur choisit celui avec la plus grande valeur.
// 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
}
Voir aussi
Commentaires
https://aka.ms/ContentUserFeedback.
Bientôt disponible : Tout au long de 2024, nous allons supprimer progressivement GitHub Issues comme mécanisme de commentaires pour le contenu et le remplacer par un nouveau système de commentaires. Pour plus d’informations, consultezEnvoyer et afficher des commentaires pour