Pour clarifier ma question, commençons avec un exemple de programme: La sortie est "8", ce qui signifie que les 56 bits (7 octets) que je veux packer sont emballés. dans 8 octets, apparemment gaspillant un octet entier. Curieux de savoir comment le compilateur posa ces morceaux dans la mémoire, j'ai essayé de rédiger des valeurs spécifiques sur int Main (int Argc, Char ** argv) p> de manière prévisible, sur x86_64 à l'aide de Visual Studio 2010, ce qui suit se produit: p> etc. p> Oubliez la portabilité pendant un moment et supposez que vous vous souciez d'une CPU, d'un compilateur et d'un environnement d'exécution. Pourquoi VC ++ ne peut-il pas emballer cette structure en 7 octets? Est-ce une chose de mots? MSDN Docs sur & C CODE>, par exemple: p>
#pragma pack code> dit "L'alignement d'un membre sera sur une limite qui est soit un multiple de N [1 dans mon cas], soit un multiple de la taille du membre, selon la taille inférieure." Quelqu'un peut-il me donner une idée de la raison pour laquelle je reçois une taille de 8 et non 7? P> p>
5 Réponses :
Les champs de bit sont stockés dans le type que vous définissez. Puisque vous utilisez non signé INT code>, et il ne contient pas dans un seul
non signé INT code> puis le compilateur doit utiliser un deuxième entier et stocker les 24 derniers bits dans ce dernier entier . P>
Non c'est faux. Le compilateur peut stocker des champs de bits dans n'importe quel type qu'il souhaite.
@ABYX Cela va à l'encontre de toutes les autres réponses et commencient ici. Si vous avez quelque chose à soutenir votre affirmation, nous aimerions le voir.
Eh bien, vous utilisez Unsigné Int qui se trouve être 32 bits dans ce cas. La limite suivante (pour s'adapter au Bitfield) pour UNSIGED INT est 64 bits => 8 octets. P>
PST a raison. Les em> les membres em> sont alignés sur les limites de 1 octet (ou plus petit, puisqu'il s'agit d'un bitfield). La structure générale a la taille 8 et est alignée sur une limite de 8 octets. Cela est conforme à la standard et à l'option code> code>. Les docs ne disent jamais qu'il n'y aura pas de rembourrage à la fin. P>
La question n'est pas avec le rembourrage à la fin, mais avec le fait que les champs de bit sont emballés dans des unités intérieures du type Bitfield. La structure n'a pas de rembourrage du tout, seulement deux non signé INT code>.
@David, la norme indique (§6.7.2.1), "Un bit-Fi est interprété comme un type d'entiers signé ou non signé composé du nombre spécifié de bits. [...] Une implémentation peut allouer une unité de stockage adressable suffisamment grande tenir un bit-fid. " Donc, je ne pense pas que non signé INT code> signifie qu'il doit réellement utiliser
non signé INT code> comme unité de stockage, juste un type non signé avec suffisamment de bits. De plus, les champs de bits sont autorisés à interrompre les limites de l'unité de stockage. Donc, je pense qu'il y a du rembourrage à la fin.
BTW, quelle standard cherchez-vous? Ni la norme C ++ actuelle ni la FCD C ++ 0x ont la section 6.7.2.1.
Cette partie de la norme me confondre au moins. Ma justification de cet argument est que le §9.6 / 1 contient: l'expression constante [Nombre de bits] peut être plus grande que le nombre de bits dans la représentation de l'objet (3.9) du type de champ de bit; Dans ce cas, les bits supplémentaires sont utilisés comme bits de rembourrage et ne participent pas à la représentation de la valeur (3.9) du Bitfield. i>
Cela signifie que les bits de caractères non signé: 10 code> ne seront pas en mesure de stocker un entier 10 bits (dans une machine 8 bits / charme) et seront différents de
non signé courts bits: 10 code>, (supposant 16 bits bref int). À partir de celui que j'ai déduit - Je ne peux pas indiquer la norme ..., que si le compilateur n'est pas capable de tomber jusqu'à un type de représentation plus gros, il n'est probablement pas autorisé à descendre non plus. Il faudrait aussi casser le type de représentation à partir de
int code> à
short + char code> dans ce cas particulier (à nouveau en supposant que 8bit Char, 16bit Short, 32bit Int)
@David, désolé, ça vient de C99. Je n'ai pas entendu dire que C ++ est différent dans ce domaine, mais cela pourrait être.
@David, cependant, c ++ 0x §9.6 dit: "Les champs de bit sont emballés dans une unité d'allocation adressable. [Remarque: les unités d'allocation à chevauchements de bit sur certaines machines et non sur d'autres. Les bit-fi sont attribués à droite. -Left sur certaines machines, à gauche à droite sur les autres. - Note de fin] ", ce qui semble assez similaire à C99. À ma lecture, il ne dit pas que "l'unité d'allocation" (qui semble être la version C ++ de "Storage Unit") doit être un non signé INT code> (à nouveau à nouveau sur le code de l'OP).
@Matthew: Non, dans toute la section, la seule référence au type de sous-étage est la citation que j'ai ajoutée ci-dessus (§9.6 / 1) qui indique clairement que la taille déclarée de l'objet sous-jacent a un effet sur la sémantique du champ. (Si le type déclaré est inférieur au nombre de bits demandés, les bits en excès ne font pas partie de la valeur, mais servent de rembourrage) il n'impose pas explicitement comment le type sous-jacent est défini, outre le fait que la grammaire définit La déclaration de champ de bits en tant que Attribut d'identificateur de spécificateur déclineur: Expression constante i>
... avec Decl-Specififier i> défini comme (une des options) Spécificateur de type i>. Maintenant, sans autre référence à Type i> disponible dans le texte, je ne peux que supposer que type sous-jacent i> fait référence au spécificateur de type i> dans le < i> déclin-spécificateur i>, lequel dans l'exemple est non signé INT code>. C'est pourquoi j'ai déjà mentionné Avant que cette partie de la norme ne semble pas vraiment Clear i> pour moi.
@David, je ne voulais pas dire que le type déclaré n'a aucun effet. Vous avez clairement raison que la clause Bits de rembourrage est basée sur le type déclaré. Mon point principal est que l'unité de stockage / l'unité d'allocation ne doit pas nécessairement être identique au type déclaré. Je suis d'accord que la norme pourrait être plus claire.
@Matthew: Nous acceptons ensuite de ne pas être d'accord :), et en ce que la norme n'est pas aussi claire que possible. En tout cas, même si j'ai accepté votre justification, il n'ya pas de combinaison de types de stockage que le compilateur peut prendre pour l'entrée donnée qui maintiendrait la sémantique et ne prendrait que 7 octets de stockage sans modifier le comportement prévu selon le §9.6 / 1. . Donc, retour à la carré, il n'a rien à voir avec le rembourrage à la fin de la structure.
MSVC ++ attribue toujours au moins une unité de mémoire correspondant au type que vous avez utilisé pour votre champ de bit. Vous avez utilisé Fondamentalement, MSVC ++ interprète votre Utilisez des types plus petits pour vos champs de bits ( non signé INT code>, ce qui signifie qu'un
non signé INT code> est attribué initialement, et un autre
non signé INT code> est attribué lorsque le premier est épuisé. Il n'y a aucun moyen de forcer MSVC ++ à couper la partie inutilisée du second
non signé INT code>. p>
non signé INT code> comme moyen d'exprimer les exigences alignement em> pour toute la structure. P>
non signé court code> et
non signé char code>) et regroupez les champs de bits afin qu'ils remplissent entièrement l'unité allouée - de cette façon de vous devrait être capable d'emballer les choses aussi étroites que possible. p>
Dans ce cas, il ne peut rien sauver s'il en a besoin des 15 et 16 bits, il préfère se retrouver avec au moins 9 octets parce qu'il utilise déjà 56 bits.
Non ... avec ce conseil, je peux effectivement l'emballer dans 7 octets (merci Andreyt). Je n'ai aucune idée de ce que vous voulez dire d'environ 9 octets.
@Rooke: Notez que Non signé Char Bits: 10 Code> est valide, mais probablement pas ce que vous voulez dire (ne stockera que 8 bits Valeurs et réserver 2 bits supplémentaires pour le rembourrage). C'est à dire. Il est d'une importance cruciale de regrouper les champs de bit de manière à ce que chaque champ de bit fits dans l'unité allouée.
@David Rodríguez - Dribesas: En effet. La solution nécessitait la réorganisation des champs.
Pour donner un autre intéressant illustre ce qui se passe, considérez le cas où vous souhaitez emballer une structure qui traverse une limite de type. E.G.
struct state_cost { unsigned int cost : 24; unsigned int junk : 8; }; state_packed sc; state_packed *p_sc = ≻ sc.a = 1; (*(struct state_cost *)p_sc).cost = 12345; sc.b = 1;
La documentation indique "... sera sur une frontière qui est ..."; Cependant, je ne peux pas trouver où il est dit quelque chose sur une garantie de taille.