web-dev-qa-db-fra.com

Opération de comparaison sur des entiers non signés et 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: a est SMALL: 1001

Je ne comprends pas ce qui se passe ici. Comment fonctionne l'opérateur> ici? Pourquoi "a" est-il plus petit que "b"? S'il est effectivement plus petit, pourquoi ai-je un nombre positif (1001) comme différence? 

35
Gitmo

Les opérations binaires entre différents types d'intégraux sont effectuées au sein d'un type "commun" défini par les conversions arithmétiques usuelles (voir la spécification de langage, 6.3.1.8). Dans votre cas, le type "commun" est unsigned int. Cela signifie que l'opérande int (votre b) sera converti en unsigned int avant la comparaison, ainsi que dans le but d'effectuer une soustraction.

Lorsque -1 est converti en unsigned int, le résultat est la valeur maximale possible de unsigned int (identique à UINT_MAX). Inutile de dire que cela va être supérieur à votre valeur 1000 non signée, ce qui signifie que a > b est en effet faux et que a est bien small par rapport à (unsigned) b. La if de votre code doit être résolue en une branche else, qui correspond à ce que vous avez observé dans votre expérience.

Les mêmes règles de conversion s'appliquent à la soustraction. Votre a-b est réellement interprété comme étant a - (unsigned) b et le résultat est de type unsigned int. Une telle valeur ne peut pas être imprimée avec le spécificateur de format %d, car %d fonctionne uniquement avec les valeurs signed. Votre tentative d'imprimer avec %d entraîne un comportement indéfini, de sorte que la valeur que vous voyez imprimer (même si elle a une explication déterministe logique) est totalement dépourvue de sens du point de vue du langage C.

Edit: En fait, je pourrais me tromper à propos du comportement non défini. Selon la spécification du langage C, la partie commune de la plage du type entier signé et non signé doit avoir une représentation identique (impliquant, conformément à la note de bas de page 31, "l'interchangeabilité en tant qu'arguments des fonctions"). Ainsi, le résultat de l'expression a - b est unsigned 1001 comme décrit ci-dessus et, sauf si quelque chose me manque, il est légal d'imprimer cette valeur non signée spécifique avec le spécificateur %d, car elle se situe dans la plage positive de int. Imprimer (unsigned) INT_MAX + 1 avec %d ne serait pas défini, mais 1001u suffirait.

44
AnT

Sur une implémentation typique où int est 32 bits, -1 lors de la conversion en unsigned int est 4 294 967 295, ce qui est bien supérieur à 1000. 

Même si vous traitez la soustraction dans un monde unsigned, 1000 - (4,294,967,295) = -4,294,966,295 = 1,001 qui correspond à ce que vous obtenez.

C'est pourquoi gcc crachera un avertissement lorsque vous comparerez unsigned à signed. (Si vous ne voyez pas d'avertissement, passez l'indicateur -Wsign-compare.)

13
kennytm
 #include<stdio.h>
 int main()
 {
   int a = 1000;
   signed int b = -1, c = -2;
   printf("%d",(unsigned int)b);
   printf("%d\n",(unsigned int)c);
   printf("%d\n",(unsigned int)a);

   if(1000>-1){
      printf("\ntrue");
   }
   else 
     printf("\nfalse");
     return 0;
 }

Pour cela, vous devez comprendre la priorité des opérateurs

  1. Les opérateurs relationnels travaillent de gauche à droite ...

    si (1000> -1)

puis tout d’abord, il passera -1 en entier non signé parce que int est considéré par défaut comme un nombre non signé et qu’il est supérieur au nombre signé 

-1 deviendra le nombre non signé, il se changera en un très grand nombre 

0
harsh

Vous effectuez une comparaison non signée, c’est-à-dire une comparaison de 1000 à 2 ^ 32 - 1.

La sortie est signée à cause de% d dans printf.

N.B. Parfois, le comportement lorsque vous mélangez des opérandes signés et non signés est spécifique au compilateur. Je pense qu'il est préférable de les éviter et de lancer des sorts en cas de doute.

0
Antti Huima

Le matériel est conçu pour comparer signature à signature et non signée à non signée. 

Si vous souhaitez obtenir le résultat arithmétique, convertissez d'abord la valeur non signée en un type signé plus grand. Sinon, le compilateur supposera que la comparaison se fait réellement entre des valeurs non signées.

Et -1 est représenté par 1111..1111, ce qui en fait une très grande quantité ... Le plus grand ... Lorsqu'il est interprété comme non signé.

0
DigitalRoss

Trouvez un moyen facile de comparer, peut-être utile lorsque vous ne pouvez pas vous débarrasser de la déclaration non signée ((par exemple, [NSArray count])), il suffit de forcer le "unsigned int" à un "int".

S'il vous plait corrigez moi si je me trompe.

if (((int)a)>b) {
    ....
}
0
chenyi1976