J'ai vu le code ci-dessous dans cet article Quora :
#include <stdio.h>
struct mystruct { int enabled:1; };
int main()
{
struct mystruct s;
s.enabled = 1;
if(s.enabled == 1)
printf("Is enabled\n"); // --> we think this to be printed
else
printf("Is disabled !!\n");
}
En C et C ++, la sortie du code est inattendue ,
Est désactivé !!
Bien que l'explication relative au "bit de signe" soit donnée dans ce post, je suis incapable de comprendre comment il est possible que nous définissions quelque chose et que cela ne reflète pas tel quel.
Quelqu'un peut-il donner une explication plus élaborée?
Remarque : les deux balisesc & c ++sont nécessaires, car leurs normes diffèrent légèrement pour décrire les champs de bits. Voir les réponses pour la spécification C et la spécification C ++ .
int
je pense qu'il ne peut contenir que les valeurs0
et-1
.struct mystruct { unsigned int enabled:1; };
?Réponses:
Les champs de bits sont incroyablement mal définis par la norme. Compte tenu de ce code
struct mystruct {int enabled:1;};
, alors nous ne savons pas :int:n
Indique si un champ de bits doit être considéré comme signé ou non signé.Concernant la dernière partie, C17 6.7.2.1/10 dit:
Note non normative expliquant ce qui précède:
Dans le cas où le champ de
signed int
bits doit être considéré comme et que vous faites un peu de taille1
, alors il n'y a pas de place pour les données, uniquement pour le bit de signe. C'est la raison pour laquelle votre programme peut donner des résultats étranges sur certains compilateurs.Bonnes pratiques:
int
type signé pour toute forme de manipulation de bits.la source
Vous demandez-vous pourquoi il compile et vous donne une erreur?
Oui, cela devrait idéalement vous donner une erreur. Et c'est le cas, si vous utilisez les avertissements de votre compilateur. Dans GCC, avec
-Werror -Wall -pedantic
:La raison pour laquelle cela est laissé à la définition de l'implémentation par rapport à une erreur peut avoir plus à voir avec les utilisations historiques, où exiger un cast signifierait casser l'ancien code. Les auteurs de la norme peuvent penser que les avertissements ont suffi à combler les lacunes des personnes concernées.
Pour ajouter un peu de prescriptivisme, je ferai écho à la déclaration de @ Lundin: "N'utilisez jamais de champs de bits pour quelque raison que ce soit." Si vous avez le genre de bonnes raisons d'obtenir des détails de bas niveau et spécifiques sur la disposition de votre mémoire qui vous amèneraient à penser que vous aviez besoin de champs de bits en premier lieu, les autres exigences associées que vous avez presque certainement se heurteront à leur sous-spécification.
(TL; DR - Si vous êtes assez sophistiqué pour légitimement «avoir besoin» de champs de bits, ils ne sont pas assez bien définis pour vous servir.)
la source
char
, la prise en charge des octets qui ne sont pas 8 bits, etc.Il s'agit d'un comportement défini par l'implémentation. Je suppose que les machines sur lesquelles vous exécutez ceci utilisent des entiers signés à complément double et les traitent
int
dans ce cas comme un entier signé pour expliquer pourquoi vous n'entrez pas si une partie vraie de l'instruction if.déclare
enable
comme un champ de bits de 1 bit. Puisqu'il est signé, les valeurs valides sont-1
et0
. Définir le champ sur les1
débordements de ce bit-1
(il s'agit d'un comportement non défini)Essentiellement, lorsqu'il s'agit d'un champ de bits signé, la valeur maximale est
2^(bits - 1) - 1
ce qui est0
dans ce cas.la source
-
et+
. Le complément de 2 n'a pas d'importance.int
comme signés dans ce cas. Il est dommage que les champs de bits soient si sous-spécifiés. C'est essentiellement ici est cette fonctionnalité, consultez votre compilateur pour savoir comment l'utiliser.Vous pourriez penser que dans le système de complément à 2, le bit le plus à gauche est le bit de signe. Tout entier signé avec le bit le plus à gauche est donc une valeur négative.
Si vous avez un entier signé de 1 bit, il n'a que le bit de signe. L'attribution
1
de ce bit unique ne peut donc définir que le bit de signe. Ainsi, lors de sa relecture, la valeur est interprétée comme négative, tout comme -1.Les valeurs qu'un entier signé de 1 bit peut contenir sont
-2^(n-1)= -2^(1-1)= -2^0= -1
et2^n-1= 2^1-1=0
la source
Conformément à la norme C ++ n4713 , un extrait de code très similaire est fourni. Le type utilisé est
BOOL
(personnalisé), mais il peut s'appliquer à n'importe quel type.Au premier coup d'œil, la partie en gras semble ouverte à l'interprétation. Cependant, l'intention correcte devient claire lorsque le
enum BOOL
est dérivé duint
.Avec le code ci-dessus, il donne un avertissement sans
-Wall -pedantic
:La sortie est:
Si
enum BOOL : int
est simplifiéenum BOOL
, alors la sortie est comme le spécifie le pasage standard ci-dessus:Par conséquent, il peut être conclu, comme peu d'autres réponses l'ont fait, que le
int
type n'est pas assez grand pour stocker la valeur "1" dans un seul champ de bits.la source
Il n'y a rien de mal dans votre compréhension des champs de bits que je peux voir. Ce que je vois, c'est que vous avez redéfini mystruct d'abord comme struct mystruct {int enabled: 1; } puis comme struct mystruct s; . Ce que vous auriez dû coder était:
la source