Vous ne devriez jamais utiliser simplement int
comme type de champ de bits si vous attendez quelque chose à propos de la valeur en dehors du fait qu'il peut contenir n
bits - selon la norme C11, il est en fait spécifié par l'implémentation si int
dans un champ de bits est signé ou non signé 6.7.2p5:
5 Chacun des ensembles multi-ensembles séparés par des virgules désigne le même type, sauf que pour les champs de bits, 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
.
Dans votre cas, int
désigne le même type que signed int
; c'est la valeur par défaut dans GCC:
Si un champ de bits “plain” int est traité comme un champ de bits signed int ou comme un champ de bits unsigned int (C90 6.5.2, C90 6.5.2.1, C99 et C11 6.7.2, C99 et C11 6.7.2.1).
Par défaut, il est traité comme signed int
mais cela peut être modifié par l'option -funsigned-bitfields
.
Il est ensuite défini par l'implémentation si les nombres signés sont en complément à un, ou en complément à deux - s'ils sont en complément à un, alors la seule valeur qui peut être stockée en 1 bit est le bit de signe, donc 0 ; donc un champ de bits signed de un bit n'a pas de sens en complément à un. Cependant, votre système utilise le complément à deux - c'est par exemple ce que GCC utilise toujours:
Si les types d'entiers signés sont représentés en signe et magnitude, en complément à deux, ou en complément à un, et si la valeur extraordinaire est une représentation de piège ou une valeur ordinaire (C99 et C11 6.2.6.2).
GCC ne supporte que les types d'entiers en complément à deux, et toutes les combinaisons de bits sont des valeurs ordinaires.
et ainsi les valeurs de bits 1
et 0
sont interprétées en termes de nombres signés en complément à deux : le premier a le bit de signe défini, donc il est négatif (-1
) et le dernier n'a pas de bit de signe défini donc il est non-négatif (0
).
Ainsi pour un champ de bits signed de 2 bits, les combinaisons de bits possibles et leurs valeurs entières sur une machine en complément à deux sont
00
- a la valeur int
0
01
- a la valeur int
1
10
- a la valeur int
-2
11
- a la valeur int
-1
Dans un champ de bits de n bits, le nombre signé minimum est - 2^(n - 1) et le maximum est 2^(n-1) - 1.
Maintenant, lorsque des opérations arithmétiques sont effectuées sur un opérande entier signé dont le rang est inférieur à int
, il est d'abord converti en un int
, et donc la valeur -1
est étendue au signe à la largeur complète de int
; la même chose se produit pour les promotions d'arguments par défaut; la valeur est signée étendue à un int
(largeur complète) lorsqu'elle est passée à printf
.
Donc si vous attendez une valeur logique d'un champ de bits d'un bit, utilisez soit unsigned bit: 1;
ou alternativement si cela doit être compris comme un drapeau booléen, _Bool bit: 1;