3 votes

Représentation du champ de bits signés

J'ai créé un champ de bits avec un champ de taille 1 bit, et utilisé int au lieu de unsigned. Plus tard, lorsque j'ai essayé de vérifier la valeur du champ, j'ai découvert que la valeur était -1. J'ai utilisé ce code pour vérifier la représentation binaire et la valeur de mon champ de bits:

#include <stdio.h>
#include <stdlib.h>

union {
    struct {
        int bit:1;
    } field;
    int rep;
} n;

int main() {

int c, k;
n.field.bit=1;
 for (c = 31; c >= 0; c--)
  {
    k = n.rep >> c;

    if (k & 1)
      printf("1");
    else
      printf("0");
  }

  printf("\n %d \n", n.field.bit);

return 0;
}

le résultat était: 00000000000000000000000000000001

-1

Dans ce cas, pourquoi la valeur de mon champ de bits est-elle -1 et est-ce toujours un nombre négatif lorsque j'utilise un int signé au lieu d'un unsigned ?

6voto

Antti Haapala Points 11542

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;

1voto

Joachim Pileborg Points 121221

Lorsque vous appelez une fonction avec des arguments variadiques (comme printf), certains arguments sont promus. Par exemple, les champs de bits subissent une promotion en entier où ils sont promus à une valeur int ordinaire. Cette promotion entraîne une extension de signe (car votre type de base pour le champ de bits est signé). Cette extension de signe le rendra -1.

Lorsque vous utilisez des champs de bits, utilisez toujours des types non signés comme base.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X