Vergleichsbetrieb bei nicht signierten und signierten Ganzzahlen
Frage
Siehe diesen Code -Snippet
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;
}
Dies gibt die Ausgabe: a ist klein: 1001
Ich verstehe nicht, was hier passiert. Wie funktioniert der> Bediener hier? Warum ist "a" kleiner als "B"? Wenn es in der Tat kleiner ist, warum bekomme ich dann eine positive Zahl (1001) als Unterschied?
Lösung
Binäre Operationen zwischen verschiedenen Integraltypen werden innerhalb eines "gemeinsamen" Typs durchgeführt, der von so genannt definiert wird übliche arithmetische Konvertierungen (Siehe die Sprachspezifikation, 6.3.1.8). In Ihrem Fall ist der "gemeinsame" Typ unsigned int
. Das bedeutet, dass int
Operand (Ihr b
) wird zu konvertiert zu unsigned int
vor dem Vergleich sowie zum Zweck der Durchführung der Subtraktion.
Wann -1
wird in konvertiert zu unsigned int
Das Ergebnis ist das maximal möglich unsigned int
Wert (gleiche wie UINT_MAX
). Unnötig zu erwähnen, dass es größer sein wird als Ihre vorzeichenlosen 1000
Wert, bedeutet das a > b
ist in der Tat falsch und a
ist in der Tat klein verglichen mit (unsigned) b
. Das if
in Ihrem Code sollte sich auflösen else
Zweig, was Sie in Ihrem Experiment beobachtet haben.
Die gleichen Konvertierungsregeln gelten für die Subtraktion. Dein a-b
wird wirklich interpretiert als a - (unsigned) b
und das Ergebnis hat Typ unsigned int
. Ein solcher Wert kann nicht mit gedruckt werden %d
Formatspezifizierer seitdem %d
funktioniert nur mit unterzeichnet Werte. Ihr Versuch, es mit zu drucken %d
führt zu undefiniertem Verhalten, so dass der Wert, den Sie sehen (auch wenn er in der Praxis eine logische deterministische Erklärung hat), aus Sicht der C -Sprache völlig bedeutungslos ist.
Bearbeiten: Eigentlich könnte ich mich in Bezug auf den undefinierten Teil des Verhaltens irren. Gemäß der C -Sprachspezifikation muss der gemeinsame Teil des Bereichs des entsprechenden signierten und unsignierten ganzzahligen Typs eine identische Darstellung haben (impliziert, wie die Fußnote 31 "Austauschbarkeit als Argumente für Funktionen"). Also das Ergebnis von a - b
Ausdruck ist nicht signiert 1001
Wie oben beschrieben, und es sei denn, es fehlt mir etwas, ist es legal, diesen spezifischen nicht signierten Wert mit zu drucken %d
Spezifizierer, da es in den positiven Bereich von fällt int
. Drucken (unsigned) INT_MAX + 1
mit %d
würde undefiniert sein, aber 1001u
ist gut.
Andere Tipps
Bei einer typischen Implementierung wo int
ist 32 -Bit, -1, wenn er zu einem konvertiert wird unsigned int
ist 4.294.967.295, was in der Tat ≥ 1000 ist.
Auch wenn Sie die Subtraktion in einem behandeln unsigned
Welt, 1000 - (4,294,967,295) = -4,294,966,295 = 1,001
Welches ist was du bekommst.
Deshalb gcc
wird eine Warnung spucken, wenn Sie vergleichen unsigned
mit signed
. (Wenn Sie keine Warnung sehen, bestehen Sie die -Wsign-compare
Flagge.)
Sie führen einen vorzeichenlosen Vergleich durch, dh 1000 bis 2^32 - 1.
Die Ausgabe wird aufgrund von %d in printf signiert.
NB manchmal ist das Verhalten, wenn Sie signierte und nicht signierte Operanden mischen, Compiler-spezifisch. Ich denke, es ist am besten, sie zu meiden und Casts zu machen, wenn Sie Zweifel haben.
Finden Sie eine einfache Möglichkeit zu vergleichen, vielleicht nützlich, wenn Sie die nicht signierte Erklärung nicht beseitigen können (z. B. [NSArray Count]), nur die "nicht signierte int" zu einem "int" erzwingen.
Bitte korrigieren Sie mich, wenn ich falsch liege.
if (((int)a)>b) {
....
}
Die Hardware ist so konzipiert, dass sie mit signiertem und nicht signiertem Unsigned unterzeichnet ist.
Wenn Sie das arithmetische Ergebnis wünschen, konvertieren Sie den nicht signierten Wert zuerst in einen größeren signierten Typ. Andernfalls geht der Compiler davon aus, dass der Vergleich wirklich zwischen nicht signierten Werten liegt.
Und -1 wird als 1111..1111 dargestellt, also ist es eine sehr große Menge ... das größte ... wenn es als nicht signiert interpretiert wird.
#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 die Vorrang vor Operatoren verstehen
Relationale Operatoren arbeiten von links nach rechts ... also, wenn es umsetzt
if (1000> -1)
Zuerst ändert sich es zuerst -1 in die unsignierte Ganzzahl, da die int standardmäßig als nicht signierte Zahl behandelt wird und es größer ist als die signierte Zahl
-1 ändert sich in die nicht signierte Zahl, sie ändert sich in eine sehr große Zahl
Beim Vergleich von a> b wobei a unsigned int type und b int type ist, B ist Typ gegossen in nicht signiertes int gegossen Daher wird der signierte Int -Wert -1 in maximaler Wert von nicht signiert ** (Bereich: 0 bis (2^32) -1) ** Daher wird a> b ie, (1000> 4294967296) falsch. Daher sonst Schleife printf ("a ist klein! %d n", ab); hingerichtet.