Remarque: cette réponse ne s'applique pas en tant que tel sur le obsolète ISO C90 standard qui est encore utilisé par de nombreux compilateurs
Tout d'abord, sur le C99, C11, l'expression -(-2147483648) == -2147483648
est en fait faux:
int is_it_true = (-(-2147483648) == -2147483648);
printf("%d\n", is_it_true);
imprime
0
Alors, comment il est possible que cela s'évalue à vrai?
La machine est à l'aide de 32 bits en complément à deux nombres entiers. L' 2147483648
est un entier constant que tout ne rentre pas en 32 bits, donc ce sera soit long int
ou long long int
selon la est le premier où il se situe. Cette niée entraînera -2147483648
- et encore une fois, même si le nombre -2147483648
peut s'adapter à un entier de 32 bits, l'expression -2147483648
se compose d'un >32 bits nombre entier positif précédé unaire -
!
Vous pouvez essayer le programme suivant:
#include <stdio.h>
int main() {
printf("%zu\n", sizeof(2147483647));
printf("%zu\n", sizeof(2147483648));
printf("%zu\n", sizeof(-2147483648));
}
La sortie sur la machine, le plus probablement, de 4, 8 et 8.
Maintenant, -2147483648
annulés seront à nouveau résultat en +214783648
, ce qui est toujours de type long int
ou long long int
, et tout va bien.
En C99, C11, la constante entière expression -(-2147483648)
est bien définie sur l'ensemble conforme implémentations.
Maintenant, lorsque cette valeur est affectée à une variable de type int
, avec 32 bits et en complément à deux de la représentation, la valeur n'est pas représentable dans - les valeurs sur 32 bits en complément de 2 seraient de l'ordre de -2147483648 à 2147483647.
La norme C11 6.3.1.3p3 dit ce qui suit entier conversions:
- [Lorsque] le nouveau type est signé et que la valeur ne peut pas être représenté, soit le résultat est la mise en œuvre défini ou d'une mise en œuvre définies par le signal est déclenché.
Qui est, le C standard n'est pas réellement définir ce que la valeur serait dans ce cas, ou de ne pas exclure la possibilité que l'exécution du programme s'arrête à cause d'un signal d'être posée, mais laisse à la mise en œuvre (c'est à dire des compilateurs) pour décider de la façon de le gérer (C11 3.4.1):
la mise en œuvre définies par le comportement
un comportement non spécifié où chaque mise en œuvre des documents de la façon dont le choix est fait
et (3.19.1):
mise en valeur définie
valeur quelconque où chaque mise en œuvre des documents de la façon dont le choix est fait
Dans votre cas, la mise en œuvre définies par le comportement, c'est que la valeur est le 32 plus bas bits de [*]. En raison de la 2 en complément, le (long) de long int valeur 0x80000000
a le bit 31 jeu et tous les autres bits effacé. En 32 bits en complément à deux entiers le bit 31 est le bit de signe - signifie que le nombre est négatif; tous les bits à zéro signifie que la valeur est le minimum de nombre représentable, c'est à dire INT_MIN
.
[*] GCC documents de sa mise en œuvre définies par le comportement dans ce cas comme suit:
Le résultat, ou le signal soulevées par, la conversion d'un nombre entier à un nombre entier signé de type lorsque la valeur ne peut pas être représenté dans un objet de ce type (C90 6.2.1.2, C99 et C11 6.3.1.3).
Pour la conversion d'un type de largeur N
, la valeur est réduite modulo 2^N
la portée de ce type; aucun signal n'est soulevée.