-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!
-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.
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
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.
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
, ouwchar_t
dont le rang de conversion entier (4.13) est inférieur au rang de int peut être converti en une prvalue de typeint
siint
peut représenter toutes les valeurs du type source; sinon, la prvalue source peut être convertie en une prvalue de typeunsigned int
.
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.
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
).