Calcul des plages de types de données en C

Je travaille sur K & R Second Edition, et je ne comprends pas pourquoi j’obtiens un certain résultat. Le problème que je résous est le calcul des limites supérieure et inférieure pour les types de données. Plus précisément:

“Ecrivez un programme pour déterminer les plages des variables char, short, int et long, signées ou non, en imprimant les valeurs appropriées à partir des en-têtes standard et par calcul direct. types de points. ”

J’ai appris à propos des opérateurs de bits et du complément à deux, et j’ai une solution qui, à mon avis, devrait fonctionner pour les types de données signés, mais plutôt pour les types de données non signés, ce qui n’a aucun sens pour moi. Voici le code:

#include  main() { signed int i; i = ~0; i >>= 1; printf("Upper limit: %d\n", i); printf("Lower limit: %d\n", -i -1); } 

Ainsi, -1 sera imprimé pour la limite supérieure et 0 pour la limite inférieure. Cependant, si je change i en un unsigned int, j’obtiens le résultat que j’attendais (2147483647 et -2147483648). Je ne peux pas comprendre cela, car je crois comprendre qu’un int non signé ne peut jamais être inférieur à 0, et qu’un int signé devrait fonctionner avec ces opérateurs au niveau du bit, c’est-à-dire que s’il s’agit d’un système 32 bits,

 ~0 == 11111111111111111111111111111111 

, et

 ~0 >> 1 == 011111111111111111111111111111111, or 2147483647. 

Une idée où je vais mal?

Sortie:

  1. Remarque:
    “Dans l’expression i >>= 1 , une valeur négative est décalée vers la droite. La norme C dit qu’il s’agit d’une opération définie par l’implémentation et de nombreuses implémentations le définissent comme un décalage arithmétique. Dans un décalage arithmétique, le bit le plus significatif est inchangé (conserve le bit de poids fort (bit signé) = 1 ) “.

    (Vous pouvez lire: Les nombres négatifs dans C qui se déplacent vers la droite >> dépendent du compilateur, qu’il s’agisse d’un décalage simple ou non, mais probablement dans votre cas, il s’agit d’un décalage arithmétique.)

    Pour cette raison après le code:

      i = ~0; i >>= 1; 

    i rest ~0 . c’est-à-dire en binary == 11111111111111111111111111111111 .

    Et parce que ~0 == 11111111111111111111111111111111 est == 2’c complément de 1 c’est-à-dire -1 .

    Ainsi, lorsque vous imprimez avec la chaîne de format %d , print -1 . Vous devez utiliser %u pour imprimer la valeur maximale non signée == ~0 .

    Important à noter ici:

    §6.2.6.2 Langue 45 , © ISO / CEI ISO / CEI 9899: 201x

    (complément des uns). Laquelle de ces conditions est implementation-defined , ainsi que par le fait de savoir si la valeur avec le bit de signe 1 et tous les bits de valeur zéro (pour les deux premiers), ou avec le bit de signe et tous les bits de valeur 1 (pour le complément à un), est une représentation de piège ou une valeur normale. Dans le cas du signe et de la magnitude et du complément à 1, si cette représentation est une valeur normale, on l’appelle un zéro négatif.

    Votre compréhension que:

    ~0 >> 1 == 011111111111111111111111111111111 est faux! (cela peut être, mais ne se produit pas dans votre système, selon la sortie)

    ~0 >> 1 == 111111111111111111111111111111111 , notez que le bit de poids fort (bit signé) est 1 .

    Pour le décalage non signé, essayez de suivre:

    ~0U >> 1 == 011111111111111111111111111111111

    Remarquez le suffixe U pour non signé.

  2. Deuxième printf :
    Parce que i est -1 , donc dans la deuxième expression -i - 1 == - (-1) - 1 == 1 - 1 == 0 , la sortie est donc égale à zéro: 0 .

en utilisant %d vous traitez votre valeur comme signed pour procéder par printf .

vous pouvez utiliser %u place.

ajoutée

Comme Magn3s1um l’a souligné, vous n’avez pas besoin de spécifier signed et unsigned pour votre tâche particulière, printf effectuera tout le travail pour vous.

Votre compilateur implémente >> comme décalage arithmétique. Par conséquent, le MSB conserve la valeur 1 et le décalage ne fait rien.

Autrement dit, ~ 0 >> 1 est toujours ~ 0 car le signe de décalage s’étend.

Voir ici: https://stackoverflow.com/a/7632/1974021

Vous pouvez être intéressé par les fichiers d’entête constant dans limits.h et float.h

De limits.h :

 +------------+------------------------------------------------------------------+--------------------------------+ | CHAR_BIT | Number of bits in a char object (byte) | 8 or greater | | SCHAR_MIN | Minimum value for an object of type signed char | -127 (-2^7+1) or less | | SCHAR_MAX | Maximum value for an object of type signed char | 127 (2^7-1) or greater | | UCHAR_MAX | Maximum value for an object of type unsigned char | 255 (2^8-1) or greater | | CHAR_MIN | Minimum value for an object of type char | either SCHAR_MIN or 0 | | CHAR_MAX | Maximum value for an object of type char | either SCHAR_MAX or UCHAR_MAX | | MB_LEN_MAX | Maximum number of bytes in a multibyte character, for any locale | 1 or greater | | SHRT_MIN | Minimum value for an object of type short int | -32767 (-2^15+1) or less | | SHRT_MAX | Maximum value for an object of type short int | 32767 (2^15-1) or greater | | USHRT_MAX | Maximum value for an object of type unsigned short int | 65535 (2^16-1) or greater | | INT_MIN | Minimum value for an object of type int | -32767 (-2^15+1) or less | | INT_MAX | Maximum value for an object of type int | 32767 (2^15-1) or greater | | UINT_MAX | Maximum value for an object of type unsigned int | 65535 (2^16-1) or greater | | LONG_MIN | Minimum value for an object of type long int | -2147483647 (-2^31+1) or less | | LONG_MAX | Maximum value for an object of type long int | 2147483647 (2^31-1) or greater | | ULONG_MAX | Maximum value for an object of type unsigned long int | 4294967295 (2^32-1) or greater | +------------+------------------------------------------------------------------+--------------------------------+ 

Lorsque vous effectuez le décalage de bit sur i , le compilateur voit que i est une quantité signée et effectue un décalage à droite arithmétique. Il semble que vous souhaitiez que cette ligne de code effectue un décalage logique à droite.

Changer la ligne

i >>= 1;

à

i = ((unsigned int)i) >> 1;

Alors ça marche!

 Output: Upper limit: 2147483647 Lower limit: -2147483648