Opération de comparaison sur non signés et les entiers signés
Voir cet extrait de code
int main()
{
unsigned int a = 1000;
int b = -1;
if (a>b) printf("A is BIG! %d\n", a-b);
else printf("a is SMALL! %d\n", a-b);
return 0;
}
Cela donne à la sortie: un est PETIT: 1001
Je ne comprends pas ce qui se passe ici. Comment l' > opérateur de travailler ici? Pourquoi est-ce "un" plus petit que "b"? Si il est en effet plus petit, pourquoi dois-je obtenir un nombre positif (1001) comme la différence?
- Si vous utilisez le Wsign-comparer compilateur drapeau, vous obtiendrez un avertissement pour la comparaison. Vous devriez toujours utiliser -Mur (qui comprend Wsign-comparer). Voir ici pour d'autres façons d'éviter ce problème.
- Voir ce post pour plus d'info: stackoverflow.com/q/10474769/844882
- techniquement ce n'est pas tout à fait droit, -Wsign-comparer n'est inc. avec -Mur si vous êtes à la compilation C++. Il n'est pas inclus pour C (voir ici gcc.gnu.org/onlinedocs/gcc/Warning-Options.html) je l'ai testé et je peux confirmer le code ci-dessus donne pas d'avertissement à -Mur, mais ne avec -Wsign-comparer (je suis en utilisant gcc (Ubuntu 5.2.1-22ubuntu2) 5.2.1 20151010)
Vous devez vous connecter pour publier un commentaire.
Opérations binaires entre les différents types intégraux sont effectuées au sein d'un "bien commun" type défini par d'habitude arithmétique des conversions (voir la spécification du langage, 6.3.1.8). Dans votre cas, la "commune" de type est
unsigned int
. Cela signifie queint
opérande (votreb
) seront converties àunsigned int
avant la comparaison, ainsi que pour l'exercice de la soustraction.Quand
-1
est converti àunsigned int
le résultat est le maximum possibleunsigned int
valeur (le même queUINT_MAX
). Inutile de dire, il va être plus grand que votre unsigned1000
valeur, ce qui signifie quea > b
est en effet faux eta
est en effet petit par rapport à(unsigned) b
. Leif
dans votre code doit se résoudre àelse
branche, qui est ce que vous avez observé dans votre expérience.Les mêmes règles de conversion s'appliquent à la soustraction. Votre
a-b
est vraiment interprété commea - (unsigned) b
et le résultat est de typeunsigned int
. Cette valeur ne peut pas être imprimé avec%d
spécificateur de format, depuis%d
ne fonctionne qu'avec signé valeurs. Votre tentative de l'imprimer avec%d
entraîne un comportement non défini, de sorte que la valeur que vous voyez imprimé (même si elle a une logique déterministe explication dans la pratique) est complètement dénuée de sens du point de vue du langage C.Edit: en Fait, j'ai peut-être tort sur le comportement indéfini de la partie. Selon C spécification du langage, la partie commune de la gamme de correspondants signés et non signés, de type entier doit avoir la même représentation (ce qui implique, selon la note de bas de page 31, "l'interchangeabilité que les arguments de fonctions"). Alors, le résultat de
a - b
expression est non signé1001
comme décrit ci-dessus, et si je suis absent quelque chose, il est légal pour imprimer cette valeur non signée avec%d
prescripteur, car elle s'inscrit dans la plage positive deint
. L'impression(unsigned) INT_MAX + 1
avec%d
serait pas défini, mais1001u
est fine.va_arg(ap, int)
seul n'est pas UB encore. Mais c'est en effet UB violer printf aux besoins attend à uneint
. Il semble stupide pour moi, si. Pourquoi n'ont-ils pas précisé pour le printf: "Le type de l'argument suivant doit être signé ou unsigned int, et sont dans la gamme de l'int".fprintf
description unis: (pour %d): "L'argument int est converti à ..." et "Si aucun argument n'est pas le type correct pour la spécification de conversion, le comportement est indéfini.". Donc je ne crois pas que c'est bien définie. Peut-être quelqu'un de usenet sait?x = 10 +- 10u + 10u +- 10;
? X signés ou non signés donne le même résultat!Sur une implémentation typique où
int
est de 32 bits, -1 lors de la conversion d'ununsigned int
est 4,294,967,295 qui est en effet ≥ 1000.Même si vous traiter de la soustraction dans un
unsigned
monde,1000 - (4,294,967,295) = -4,294,966,295 = 1,001
qui est ce que vous obtenez.C'est pourquoi
gcc
va cracher un avertissement lorsque vous comparezunsigned
avecsigned
. (Si vous ne voyez pas un avertissement, passer le-Wsign-compare
drapeau.)UINT_MAX
est 4,294,967,295. Voir aussi stackoverflow.com/questions/1863153Vous faites unsigned comparaison, c'est à dire la comparaison de 1000 à 2^32 - 1.
La sortie est signé en raison de %d dans le printf.
N. B. parfois, le comportement lorsque vous mélangez les entiers signés et non signés opérandes est spécifique au compilateur. Je pense que c'est mieux de les éviter et de ne jette dans le doute.
int
etunsigned int
opérandes sont évalués comme non signés, la soustraction et le résultat est, bien sûr, non signé.Trouver un moyen facile de comparer, peut-être utile lorsque vous ne pouvez pas vous débarrasser de non signé de déclaration (par exemple, [NSArray count]), juste à la force de la "unsigned int" à un "int".
S'il vous plaît corrigez-moi si je me trompe.
Le matériel est conçu pour comparer signé signé et non signé non signé.
Si vous souhaitez que l'arithmétique de raison, de convertir la valeur non signée à un plus grand type signé en premier. Sinon le compilateur supposera que la comparaison est vraiment entre des valeurs non signées.
Et -1 est représenté comme 1111..1111, de sorte qu'il a une très grande quantité ... Le plus gros ... s'il est interprété comme non signé.
Pour cela, vous devez comprendre la priorité des opérateurs
Opérateurs relationnels œuvres de gauche à droite ...
alors quand il s'agit
si(1000>-1)
alors tout d'abord il va changer -1 non signé entier, car int par défaut est traité comme non signé nombre et de la portée de la plus grande que l'signé nombre
-1 changement dans le nombre non signé ,il se transforme en un très grand nombre
tout en comparant les a>b, où a est de type unsigned int et b est de type int, b est de type coulé à unsigned int signée int valeur -1 est convertie en une valeur MAX de non signé**(plage: 0 à (2^32)-1 )**
Ainsi, a>b, c'est à dire, (1000>4294967296) devient faux. Donc le reste de la boucle printf("a est plus PETIT! %d\n", a-b); exécuté.