web-dev-qa-db-fra.com

(-2147483648> 0) renvoie vrai en C ++?

-2147483648 est le plus petit entier pour le type entier avec 32 bits, mais il semble qu'il débordera dans la phrase if(...):

if (-2147483648 > 0)
    std::cout << "true";
else
    std::cout << "false";

Ceci imprimera true dans mes tests. Cependant, si nous convertissons un entier en -2147483648, le résultat sera différent:

if (int(-2147483648) > 0)
    std::cout << "true";
else
    std::cout << "false";

Ceci imprimera false.

Je suis confus. Quelqu'un peut-il donner une explication à ce sujet?


Mise à jour du 02-05-2012:

Merci pour vos commentaires, dans mon compilateur, la taille de int est de 4 octets. J'utilise VC pour des tests simples. J'ai modifié la description dans ma question.

C’est beaucoup de très bonnes réponses dans ce billet, AndreyT a donné une explication très détaillée sur le comportement du compilateur sur cette entrée et sur la manière dont cet entier minimum a été implémenté. qPCR4vir a par contre donné quelques "curiosités" liées et la manière dont les entiers sont représentés. Tellement impressionnant!

238
benyl

-2147483648 n'est pas un "nombre". Le langage C++ ne prend pas en charge les valeurs littérales négatives.

-2147483648 est en fait une expression: une valeur littérale positive 2147483648 avec unaire - opérateur devant. Valeur 2147483648 est apparemment trop grand pour le côté positif de la plage int sur votre plate-forme. Si vous tapez long int ayant une plus grande portée sur votre plate-forme, le compilateur devrait automatiquement supposer que 2147483648 a long int type. (En C++ 11, le compilateur devrait également prendre en compte long long int _ type.) Cela permettrait au compilateur d’évaluer -2147483648 dans le domaine de type plus grand et le résultat serait négatif, comme on pourrait s'y attendre.

Cependant, apparemment dans votre cas, la plage de long int est identique à la plage de int et, en général, il n’existe pas de type entier dont la plage est supérieure à celle de int sur votre plate-forme. Cela signifie formellement que la constante positive 2147483648 déborde de tous les types d'entiers signés disponibles, ce qui signifie que le comportement de votre programme n'est pas défini. (Il est un peu étrange que la spécification de langue opte pour un comportement indéfini dans de tels cas, au lieu d'exiger un message de diagnostic, mais c'est comme ça.)

En pratique, compte tenu du fait que le comportement est indéfini, 2147483648 pourrait être interprété comme une valeur négative dépendant de la mise en œuvre, qui devient positive après avoir été unaire - appliqué à cela. Certaines implémentations peuvent également décider d’utiliser des types non signés pour représenter la valeur (par exemple, dans C89/90, les compilateurs étaient tenus d’utiliser unsigned long int, mais pas en C99 ou C++). Les implémentations sont autorisées à faire n'importe quoi, car le comportement n'est de toute façon pas défini.

En remarque, c’est la raison pour laquelle des constantes comme INT_MIN sont généralement définis comme

#define INT_MIN (-2147483647 - 1)

au lieu de l'apparence plus simple

#define INT_MIN -2147483648

Ce dernier ne fonctionnerait pas comme prévu.

386
AnT

Le compilateur (VC2012) promeut les entiers "minimum" pouvant contenir les valeurs. Dans le premier cas, signed int (et long int) ne peut pas (avant que le signe ne soit appliqué), mais unsigned int peut: 2147483648 a unsigned int ???? type. Dans la seconde, vous forcez int à partir de unsigned.

const bool i= (-2147483648 > 0) ;  //   --> true

avertissement C4146: opérateur moins unaire appliqué à type non signé , résultat toujours non signé

Voici les "curiosités" liées:

const bool b= (-2147483647      > 0) ; //  false
const bool i= (-2147483648      > 0) ; //  true : result still unsigned
const bool c= ( INT_MIN-1       > 0) ; //  true :'-' int constant overflow
const bool f= ( 2147483647      > 0) ; //  true
const bool g= ( 2147483648      > 0) ; //  true
const bool d= ( INT_MAX+1       > 0) ; //  false:'+' int constant overflow
const bool j= ( int(-2147483648)> 0) ; //  false : 
const bool h= ( int(2147483648) > 0) ; //  false
const bool m= (-2147483648L     > 0) ; //  true 
const bool o= (-2147483648LL    > 0) ; //  false

norme C++ 11 :

2.14.2 Littéraux entiers [Lex.icon]

Un littéral entier est une séquence de chiffres qui n'a ni période ni partie d'exposant. Un littéral entier peut avoir un préfixe qui spécifie sa base et un suffixe qui spécifie son type.

Le type d'un littéral entier est le premier de la liste correspondante dans laquelle sa valeur peut être représentée.

enter image description here

Si un littéral entier ne peut être représenté par aucun type de sa liste et qu'un type entier étendu (3.9.1) peut représenter sa valeur, il peut avoir ce type entier étendu. Si tous les types de la liste du littéral sont signés, le type entier étendu doit être signé. Si tous les types de la liste pour le littéral sont non signés, le type entier étendu doit être non signé. Si la liste contient à la fois des types signés et non signés, le type entier étendu peut être signé ou non signé. Un programme est mal formé si l’une de ses unités de traduction contient un littéral entier qui ne peut être représenté par aucun des types autorisés.

Et ce sont les règles de promotions pour les entiers dans la norme.

4.5 Promotions intégrales [conv.prom]

Une valeur d'un type entier différent de bool, char16_t, char32_t, ou wchar_t dont le rang de conversion entier (4.13) est inférieur au rang de int peut être converti en une prvalue de type int si int peut représenter toutes les valeurs du type source; sinon, la prvalue source peut être convertie en une prvalue de type unsigned int.

43
qPCR4vir

En bref, 2147483648 déborde sur -2147483648, et (-(-2147483648) > 0) est true.

This c'est comment 2147483648 ressemble à binaire.

De plus, dans le cas de calculs binaires signés, le bit le plus significatif ("MSB") est le bit de signe. Cette question peut aider à expliquer pourquoi.

7
drzymala

Parce que -2147483648 Est en réalité 2147483648 Et que la négation (-) Lui est appliquée, le nombre n'est pas ce que vous attendez. C'est en fait l'équivalent de ce pseudocode: operator -(2147483648)

Maintenant, en supposant que votre compilateur a sizeof(int) égale à 4 Et que CHAR_BIT Est défini comme 8, Cela ferait déborder le maximum 2147483648 valeur signée d'un entier (2147483647). Alors, quel est le maximum plus un? Permet de résoudre ce problème avec un entier complémentaire de 4 bits, 2s.

Attendez! 8 déborde le nombre entier! Qu'est-ce qu'on fait? Utilisez sa représentation non signée de 1000 Et interprétez les bits comme un entier signé. Cette représentation nous laisse avec -8 Étant appliquée la négation du complément à 2 qui résulte en 8, Qui, comme nous le savons tous, est supérieure à 0.

C'est pourquoi <limits.h> (Et <climits>) Définissent généralement INT_MIN Comme ((-2147483647) - 1) - de sorte que le nombre entier maximum signé (0x7FFFFFFF) Est annulé (0x80000001), Puis décrémenté (0x80000000).

4
Cole Johnson