wake-up-neo.com

Vergleichsoperation bei vorzeichenlosen und vorzeichenbehafteten Ganzzahlen

Siehe diesen Code-Ausschnitt

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;
}   

Daraus ergibt sich die Ausgabe: a ist SMALL: 1001

Ich verstehe nicht, was hier passiert. Wie funktioniert der Operator hier? Warum ist "a" kleiner als "b"? Wenn es tatsächlich kleiner ist, warum bekomme ich eine positive Zahl (1001) als Differenz? 

35
Gitmo

Binäre Operationen zwischen verschiedenen Integraltypen werden innerhalb eines "üblichen" Typs ausgeführt, der durch sogenannte usual-Arithmetik-Konvertierungen definiert wird (siehe Sprachspezifikation, 6.3.1.8). In Ihrem Fall lautet der "allgemeine" Typ unsigned int. Das bedeutet, dass int-Operand (Ihre b) vor dem Vergleich sowie zum Zwecke der Subtraktion in unsigned int konvertiert wird.

Wenn -1 in unsigned int konvertiert wird, ist das Ergebnis der maximal mögliche unsigned int-Wert (wie UINT_MAX). Es ist unnötig zu sagen, dass es größer sein wird als Ihr vorzeichenloser 1000-Wert, was bedeutet, dass a > b tatsächlich falsch ist und a tatsächlich small ist, verglichen mit (unsigned) b. Die Variable if in Ihrem Code sollte sich in den Zweig else auflösen, wie Sie es in Ihrem Experiment beobachtet haben.

Für die Subtraktion gelten dieselben Umrechnungsregeln. Ihr a-b wird wirklich als a - (unsigned) b interpretiert und das Ergebnis hat den Typ unsigned int. Dieser Wert kann nicht mit dem Formatbezeichner %d gedruckt werden, da %d nur mit den Werten von signed funktioniert. Ihr Versuch, es mit %d zu drucken, führt zu undefiniertem Verhalten. Daher ist der Wert, den Sie gedruckt sehen (auch wenn er in der Praxis eine logische deterministische Erklärung hat) aus Sicht der Sprache C völlig bedeutungslos.

Edit: Eigentlich könnte ich mich bezüglich des undefinierten Verhaltensteils irren. Gemäß der C-Sprachspezifikation muss der gemeinsame Teil des Bereichs des entsprechenden vorzeichenbehafteten und vorzeichenlosen Integer-Typs eine identische Darstellung haben (was gemäß Fußnote 31 "Austauschbarkeit als Argumente für Funktionen" impliziert). Das Ergebnis des a - b-Ausdrucks ist also wie oben beschrieben vorzeichenlos 1001. Wenn mir etwas fehlt, ist es zulässig, diesen bestimmten vorzeichenlosen Wert mit dem %d-Bezeichner zu drucken, da er in den positiven Bereich von int fällt. Das Drucken von (unsigned) INT_MAX + 1 mit %d wäre undefiniert, aber 1001u ist in Ordnung.

44
AnT

Bei einer typischen Implementierung, bei der int 32-Bit ist, ist -1 bei Umwandlung in einen unsigned int 4.294.967.295, was tatsächlich ≥ 1000 ist. 

Selbst wenn Sie die Subtraktion in einer unsigned-Welt behandeln, 1000 - (4,294,967,295) = -4,294,966,295 = 1,001 erhalten Sie diese.

Deshalb gibt gcc eine Warnung aus, wenn Sie unsigned mit signed vergleichen. (Wenn Sie keine Warnung sehen, übergeben Sie das Flag -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;
 }

Dafür müssen Sie den Vorrang der Operatoren verstehen

  1. Relational Operators arbeitet von links nach rechts ... Wenn es darum geht

    wenn (1000> -1)

dann ändert sich zunächst -1 in eine vorzeichenlose Ganzzahl, da int standardmäßig als vorzeichenlose Zahl behandelt wird und der Bereich größer als die vorzeichenbehaftete Zahl ist 

-1 ändert sich in eine vorzeichenlose Zahl, ändert sich in eine sehr große Zahl 

0
harsh

Sie führen einen vorzeichenlosen Vergleich durch, d. H. Den Vergleich von 1000 mit 2 ^ 32 - 1.

Die Ausgabe ist wegen% d in printf signiert.

N.B. Manchmal ist das Verhalten beim Mischen von signierten und unsignierten Operanden compilerspezifisch. Ich denke, es ist am besten, sie zu vermeiden und im Zweifelsfall Casts durchzuführen.

0
Antti Huima

Die Hardware ist dafür ausgelegt, signierte mit nicht signierten und nicht signierten Signalen zu vergleichen. 

Wenn Sie das arithmetische Ergebnis erhalten möchten, konvertieren Sie zuerst den vorzeichenlosen Wert in einen größeren vorzeichenbehafteten Typ. Andernfalls nimmt der Compiler an, dass der Vergleich wirklich zwischen vorzeichenlosen Werten besteht.

Und -1 wird als 1111..1111 dargestellt, also eine sehr große Menge ... Die größte ... Wenn sie als nicht signiert interpretiert wird.

0
DigitalRoss

Finden Sie einen einfachen Weg, um zu vergleichen, vielleicht nützlich, wenn Sie nicht signierte Deklarationen nicht loswerden können (z. B. [NSArray count]).

Bitte korrigieren Sie mich, wenn ich falsch liege.

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