Gestion de la mémoire des champs de bits en C

Pour comprendre le stockage de la mémoire du champ de bits, j’ai créé le programme de test ci-dessous.

#include  int main() { int a; typedef struct { int b7 : 1; int b6 : 1; int b5 : 1; int b4 : 1; int b3 : 1; int b2 : 1; int b1 : 1; int b0 : 1; } byte; byte ab0 = {0,0,0,0,0,0,0,1}; a = *(int*)&ab0; printf("ab0 is %x \n",a); byte ab1 = {0,0,0,0,0,0,1,0}; a = *(int*)&ab1; printf("ab1 is %x \n",a); byte ab2 = {0,0,0,0,0,1,0,0}; a = *(int*)&ab2; printf("ab2 is %x \n",a); byte ab3 = {0,0,0,0,1,0,0,0}; a = *(int*)&ab3; printf("ab3 is %x \n",a); byte ab4 = {0,0,0,1,0,0,0,0}; a = *(int*)&ab4; printf("ab4 is %x \n",a); byte ab5 = {0,0,1,0,0,0,0,0}; a = *(int*)&ab5; printf("ab5 is %x \n",a); byte ab6 = {0,1,0,0,0,0,0,0}; a = *(int*)&ab6; printf("ab6 is %x \n",a); byte ab7 = {1,0,0,0,0,0,0,0}; a = *(int*)&ab7; printf("ab7 is %x \n",a); return 0; } 

Comstackr et exécuter

 gcc -Wall test.c ./a.out ab0 is 80 ab1 is 40 ab2 is 20 ab3 is 10 ab4 is 8 ab5 is 4 ab6 is 2 ab7 is 1 

Même sortie lorsque je lance du code en ligne http://codepad.org/ntqyuixp

Je ne suis pas capable de comprendre sa sortie.

Résultat attendu: selon ce que je comprends, le résultat devrait être comme

 ab0 is 1 ab1 is 2 ab2 is 4 ab3 is 8 ab4 is 10 ab5 is 20 ab6 is 40 ab7 is 80 
  • S’il vous plaît laissez-moi savoir ce qui me manque.

  • Endianness joue-t-il un rôle?

  • Comment le code devrait-il être écrit pour mon comportement attendu?

L’ordre des bits dans un champ de bits est défini par l’implémentation. L’implémentation a une définition différente de celle à laquelle vous vous attendiez – et c’est presque tout ce qu’il y a à dire à ce sujet.

Presque tout ce qui concerne les champs de bits est défini par l’implémentation.

ISO / IEC 9899: 2011 §6.7.2.1 Spécificateurs de structure et d’union

¶4 L’expression qui spécifie la largeur d’un champ de bits doit être une expression de type entier avec une valeur non négative qui ne dépasse pas la largeur d’un object du type spécifié si les deux points et l’expression ont été omis. 122) Si la valeur est zéro, la déclaration ne doit pas avoir de déclarant.

¶5 Un champ de bits doit avoir un type qui est une version qualifiée ou non qualifiée de _Bool , signed int , unsigned int ou un autre type défini par l’implémentation. Il est défini par l’implémentation si les types atomiques sont autorisés.

¶9 Un membre d’une structure ou d’une union peut avoir un type d’object complet autre qu’un type modifié de façon variable. 123) De plus, un membre peut être déclaré comme étant composé d’un nombre spécifié de bits (y compris un bit de signe, le cas échéant). Un tel membre est appelé un champ binary; 124) sa largeur est précédée d’un deux-points.

¶10 Un champ de bits est interprété comme ayant un type d’entier signé ou non signé composé du nombre de bits spécifié. 125) Si la valeur 0 ou 1 est stockée dans un champ binary de largeur différente de zéro et de type _Bool , la valeur du champ binary doit être égale à la valeur stockée; un _Bool bits _Bool a la sémantique d’un _Bool .

¶11 Une implémentation peut allouer toute unité de stockage adressable suffisamment grande pour contenir un champ de bits. S’il rest suffisamment d’espace, un champ binary qui suit immédiatement un autre champ binary dans une structure doit être compressé en bits adjacents de la même unité. Si l’espace rest insuffisant, le champ de bit qui ne rentre pas est placé dans l’unité suivante ou chevauche des unités adjacentes. L’ordre d’atsortingbution des champs de bits au sein d’une unité (d’ordre élevé à faible ou faible à élevé) est défini par la mise en œuvre. L’alignement de l’unité de stockage adressable n’est pas spécifié.

¶12 Une déclaration de champ de bits sans déclarateur, mais uniquement un signe deux-points et une largeur, indique un champ de bits sans nom. 126) Dans un cas particulier, un membre de structure de champ binary avec une largeur de 0 indique qu’aucun autre champ binary ne doit être placé dans l’unité dans laquelle le champ de bits précédent, le cas échéant, a été placé.

122) Alors que le nombre de bits dans un object _Bool est au moins CHAR_BIT , la largeur (nombre de bits de signe et de valeur) d’un object _Bool peut ne représenter que 1 bit.

123) Une structure ou une union ne peut pas contenir un membre avec un type modifié de manière variable, car les noms de membre ne sont pas des identificateurs ordinaires tels que définis au 6.2.3.

124) L’opérateur unaire & (adresse-de) ne peut pas être appliqué à un object de champ de bits; ainsi, il n’y a pas de pointeurs ou de tableaux d’objects de champs de bits.

125) Comme spécifié au 6.7.2 ci-dessus, si le spécificateur de type utilisé est int ou un nom de typedef défini comme int , alors il est défini par l’implémentation si le champ de bits est signé ou non signé.

126) Un membre de structure de champ de bits sans nom est utile pour que le remplissage soit conforme aux dispositions imposées en externe.

Notez ¶11 en particulier:

L’ordre d’atsortingbution des champs de bits au sein d’une unité (d’ordre élevé à faible ou faible à élevé) est défini par la mise en œuvre.

Notez également que «défini par l’implémentation» signifie que l’implémentation doit définir ce qu’elle fait. En d’autres termes, vous pouvez inspecter la documentation et la documentation doit vous indiquer ce que fait le compilateur (si le compilateur est conforme aux normes). Ceci est différent de «non spécifié» et de certains des autres termes que vous rencontrerez – un éditeur de compilateur ne changerait presque certainement pas le comportement des champs de bits de la version à la publication. En revanche, la manière dont les arguments des fonctions sont évalués, par exemple, peut varier d’une version à l’autre ou en fonction des options d’optimisation choisies au moment de la compilation, etc.

§6.5.2.2 Appels de fonction

Il y a un sharepoint séquence après les évaluations du désignateur de fonction et des arguments réels mais avant l’appel réel. Toute évaluation dans la fonction d’appel (y compris les autres appels de fonction) qui n’est pas autrement séquencée spécifiquement avant ou après l’exécution du corps de la fonction appelée est indéfiniment séquencée en ce qui concerne l’exécution de la fonction appelée. 94)

94) En d’autres termes, les exécutions de fonctions ne s’interpénètrent pas entre elles.

6.7.2 Spécificateurs de type

5 Chacun des multisets séparés par des virgules désigne le même type, sauf que pour les champs binarys, il est défini par l’implémentation si le spécificateur int désigne le même type que signed int ou le même type que unsigned int .

les champs de bits ne sont pas portables et dépendent de la machine.

Limites d’utilisation des champs de bits

Lorsque vous utilisez des champs de bits, tenez compte des problèmes suivants:

  1. Le code sera non portable car l’organisation des bits dans les octets et des octets dans les mots dépend de la machine .
  2. Vous ne pouvez pas prendre l’adresse d’un champ de bit; par conséquent, l’expression & mystruct.x est illégale si x est un identificateur de champ binary, car rien ne garantit que mystruct.x se trouve à une adresse d’octet.
  3. Les champs de bits sont utilisés pour regrouper davantage de variables dans un espace de données plus petit, mais obligent le compilateur à générer du code supplémentaire pour manipuler ces variables. Cela coûte en termes de taille de code et de temps d’exécution.

Pour Linux sur x86, le document ABI correspondant peut être trouvé ici (pdf) .

Spécifiquement lié aux champs de bits:

Les champs binarys “simples” (c’est-à-dire ceux qui ne sont ni signed ni unsigned ) ont toujours des valeurs non négatives. Bien qu’ils puissent avoir le type char , short , int ou long (qui peuvent avoir des valeurs négatives), ces champs binarys ont la même plage qu’un champ binary de même taille avec le type unsigned correspondant.

Les champs de bits obéissent aux mêmes règles de taille et d’alignement que les autres membres de la structure et de l’union, avec les ajouts suivants:

Les champs de bits sont atsortingbués de droite à gauche (du moins au plus significatif). Un champ de bits doit résider entièrement dans une unité de stockage appropriée à son type déclaré. Ainsi, un champ de bits ne traverse jamais sa limite d’unité.

Les champs de bits peuvent partager une unité de stockage avec d’autres membres struct / union , y compris les membres qui ne sont pas des champs de bits. Bien entendu, les membres de la struct occupent différentes parties de l’unité de stockage. Les types de champs de bits sans nom n’affectent pas l’alignement d’une structure ou d’une union, bien que les décalages de membres des champs de bits individuels respectent les contraintes d’alignement.

le