taille de la structure et de la variable correspondante

Si je définis une variable char

char a; 

et une structure avec un seul membre char

 struct OneChar { char a; }; 

Ces deux définitions auront-elles la taille de ‘char’ dans tous les compilateurs? Mon doute est que, si nous définissons une variable char dans la structure, cela prendra-t-il plus de taille que la taille de char en raison de la compression de la mémoire?

Cela dépend de l’architecture et du compilateur. Pour ce cas particulier, vous devriez être en sécurité, mais consultez Data Padding .

Voici un extrait :

Alignement typique des structures C sur x86

Les membres de structure de données sont stockés séquentiellement dans une mémoire, de sorte que dans la structure située en dessous du membre, Data1 précède toujours Data2 et que Data2 précède toujours Data3:

 struct MyData { short Data1; short Data2; short Data3; }; 

Si le type “court” est stocké dans deux octets de mémoire, chaque membre de la structure de données décrite ci-dessus serait aligné sur 2 octets. Les données1 seraient à l’offset 0, les données2 à l’offset 2 et les données3 à l’offset 4. La taille de cette structure serait de 6 octets.

Le type de chaque membre de la structure a généralement un alignement par défaut, ce qui signifie que, sauf demande contraire du programmeur, il sera aligné sur une limite prédéterminée. Les alignements typiques suivants sont valides pour les compilateurs de Microsoft, Borland et GNU lors de la compilation pour 32 bits x86:

  • Un caractère (un octet) sera aligné sur 1 octet.
  • Un court (deux octets) sera aligné sur deux octets.
  • Un int (quatre octets) sera aligné sur 4 octets.
  • Un float (quatre octets) sera aligné sur 4 octets.
  • Un double (huit octets) sera aligné sur 8 octets sous Windows et sur 4 octets sous Linux.

Voici une structure avec des membres de différents types, totalisant 8 octets avant la compilation:

 struct MixedData { char Data1; short Data2; int Data3; char Data4; }; 

Après la compilation, la structure de données sera complétée d’octets de remplissage pour assurer un alignement correct pour chacun de ses membres:

 struct MixedData /* after compilation */ { char Data1; char Padding0[1]; /* For the following 'short' to be aligned on a 2 byte boundary */ short Data2; int Data3; char Data4; char Padding1[3]; }; 

La taille compilée de la structure est maintenant de 12 octets. Il est important de noter que le dernier membre est complété avec le nombre d’octets requirejs pour se conformer au type le plus large de la structure. Dans ce cas, 3 octets sont ajoutés au dernier membre pour donner à la structure la taille d’un mot long.

Il est possible de modifier l’alignement des structures afin de réduire la mémoire dont elles ont besoin (ou de se conformer à un format existant) en modifiant l’alignement (ou le «compactage») du compilateur des éléments de la structure.

Si vous demandez que la structure MixedData ci-dessus soit alignée sur une limite d’un octet, le compilateur ignorera l’alignement prédéterminé des membres et aucun octet de remplissage ne sera inséré.

Bien qu’il n’existe pas de méthode standard pour définir l’alignement des membres de la structure, certains compilateurs utilisent les directives #pragma pour spécifier la compression dans les fichiers source. Voici un exemple:

 #pragma pack(push) /* push current alignment to stack */ #pragma pack(1) /* set alignment to 1 byte boundary */ struct MyPackedData { char Data1; long Data2; char Data3; }; #pragma pack(pop) /* restore original alignment from stack */ 

Cette structure aurait une taille compilée de 6 octets. Les directives ci-dessus sont disponibles dans les compilateurs de Microsoft, Borland, GNU et beaucoup d’autres.

Tant qu’il n’y a qu’un seul membre, je pense que cette hypothèse est sans danger.

Le cas que vous listez sera emballé comme une structure d’un octet sous toutes les ABI que je connaisse.

Toutefois, si vous devez gérer de manière portable des cas plus complexes, la meilleure pratique consiste à toujours utiliser sizeof(struct OneChar) lors du calcul de la taille de la mémoire et à prendre le décalage de l’adresse de champ lorsque vous devez calculer des adresses via une astuce telle que:

 (char*)&(((struct OneChar*)0)->a) - (char*)0 

Tous les objects auront la même taille, qu’ils soient isolés ou qu’ils se trouvent à l’intérieur d’une structure.

Ce qui peut arriver dans une structure, c’est qu’il y a un bourrage entre les membres … mais cela peut aussi arriver dans des variables “autonomes”.

Lorsque vous prenez la taille d’une structure, elle inclut les octets de remplissage. Mais si vous avez quelque chose comme ce qui suit:

 void fun() { char c; int n; } 

Le compilateur est libre d’insérer un remplissage pour la raison qu’il voit. Donc, le rembourrage pourrait être là dans le cas de variables autonomes, vous ne pouvez pas savoir à ce sujet comme dans le cas d’une structure.

Différents compilateurs optimiseront l’ajout de remplissage entre ou à la fin de la structure. Il n’est donc pas prudent sur tous les compilateurs ou plates-formes de supposer que la taille allouée est ce qu’il semble. Vérifiez les options de votre compilateur pour définir le remplissage de la structure.

Par exemple, Visual Studio utilise la directive #pragma pack pour remplacer les optimisations par défaut.