mise en page de mémoire en C struct
-
02-10-2019 - |
Question
J'ai un C # fond. Je suis très bien un débutant à un langage de bas niveau comme C.
En C #, la mémoire de struct
est aménagé par le compilateur par défaut. Le compilateur peut réordonner des champs de données ou pad bits supplémentaires entre les champs implicitement. Donc, je devais spécifier un attribut spécial pour modifier ce comportement pour la mise en page exacte.
AFAIK, C ne mise en mémoire ne Réorganiser ou d'un alignement struct
par défaut. Cependant, j'ai entendu il y a une petite exception qui est très difficile à trouver.
Quel est le comportement de mise en page de mémoire C? Ce qui devrait être réorganisée / aligné et non?
La solution
En C, le compilateur est autorisé à dicter un certain alignement pour chaque type primitif. Typiquement, l'alignement est la taille de ce type. Mais il est tout à la mise en œuvre spécifique.
octets de Rembourrage sont introduits de sorte que chaque objet est correctement aligné. ReOrdering n'est pas autorisé.
Peut-être tous les outils du compilateur à distance moderne #pragma pack
qui permet le contrôle de rembourrage et laisse au programmeur de se conformer à l'ABI. (Il est strictement non standard, cependant.)
De C99 §6.7.2.1:
12 Chaque membre non-champ binaire d'un la structure ou de l'objet est aligné union d'une manière définie l'implémentation adaptée au type.
Dans un 13 objet de structure, le champ non-bit les membres et les unités dans lesquelles champs de bits résident ont adresses augmentation de l'ordre dans lequel ils sont déclarés. Un pointeur vers une structure objet, converti de manière appropriée, des points de son élément initial (ou si ce membre est un champ binaire, puis à l'unité lequel il se trouve), et vice versa. Il peut y avoir des remplissages sans nom dans un objet structure, mais pas à sa début.
Autres conseils
spécifique de mise en œuvre, mais dans la pratique la règle (en l'absence de #pragma pack
ou similaire) est:
- Les membres sont stockés dans Struct l'ordre dans lequel ils sont déclarés. (Ceci est requis par la norme C99, comme mentionné ici auparavant.)
- Si nécessaire, le rembourrage est ajouté avant chaque membre struct, afin d'assurer un alignement correct.
- Chaque type primitif T nécessite un alignement d'octets de
sizeof(T)
.
Alors, compte tenu de la struct suivante:
struct ST
{
char ch1;
short s;
char ch2;
long long ll;
int i;
};
-
ch1
est à la position 0 - un octet de bourrage est inséré pour aligner ...
-
s
à décalage 2 -
ch2
est à décalage 4, immédiatement après s - 3 octets de bourrage sont insérés à aligner ...
-
ll
à 8 décalage -
i
est à 16 décalage, juste après ll - 4 octets de remplissage sont ajoutés à la fin de sorte que la structure globale est un multiple de 8 octets. Je vérifié ceci sur un système 64 bits. Les systèmes 32 bits peuvent permettre d'avoir un alignement structs 4 octets
sizeof(ST)
est 24.
Il peut être réduit à 16 octets en réorganisant les membres à éviter padding:
struct ST
{
long long ll; // @ 0
int i; // @ 8
short s; // @ 12
char ch1; // @ 14
char ch2; // @ 15
} ST;
Vous pouvez commencer par lire l'article de wikipedia d'alignement de la structure de données pour obtenir une meilleure compréhension des l'alignement des données.
De la wikipedia article :
des moyens d'alignement de données mettant les données à une mémoire de décalage égal à un multiple de la taille de mot, ce qui augmente les performances du système en raison de la façon dont la poignée de la CPU mémoire. Pour aligner les données, il peut être nécessaire d'insérer des octets vides de sens entre la fin de la dernière structure de données et le début de la prochaine, qui est le rembourrage de structure de données.
De 6.54.8 Structure-emballage Pragmas du CCG documentation:
Pour la compatibilité avec Microsoft compilateurs Windows, GCC prend en charge un ensemble des directives #pragma qui changent la alignement maximal de membres de structures (autres que zéro largeur bitfields), les syndicats et les classes ensuite définie. La valeur de n ci-dessous est toujours nécessaire d'être un petit puissance de deux et précise la nouvelle alignement en octets.
#pragma pack(n)
définit simplement le nouvel alignement.#pragma pack()
définit l'alignement de celui qui était en effet quand a commencé la compilation (voir commander également l'option de ligne -fpack-struct [=] Voir le code Gen Options).#pragma pack(push[,n])
pousse le réglage d'alignement en cours sur une pile interne et ensuite éventuellement définit le nouvel alignement.#pragma pack(pop)
rétablit le réglage d'alignement à celle enregistrée au le sommet de la pile interne (et supprime cette entrée de pile). Notez que#pragma pack([n])
n'a aucune influence sur cette pile interne; il est donc possible d'avoir#pragma pack(push)
suivie par multiple#pragma pack(n)
instances et mis au point par un seul#pragma pack(pop)
.Certaines cibles, par exemple i386 et powerpc, soutenir la
#pragma
de ms_struct qui expose une structure comme documentée__attribute__ ((ms_struct))
.
- tourne
#pragma ms_struct on
sur la mise en page pour les structures déclaré.- tourne
#pragma ms_struct off
au large de la mise en page pour les structures déclaré.#pragma ms_struct reset
retourne à la mise en page par défaut.