Ich habe den folgenden Code im Buch Computersysteme: Die Perspektive eines Programmierers, 2 / E gesehen. Dies funktioniert gut und erzeugt die gewünschte Ausgabe. Die Ausgabe kann durch die Differenz von Vorzeichen und Vorzeichen erklärt werden.
%Vor% Der obige Code liefert -1 >= 0u
, jedoch der folgende Code, der derselbe wie oben sein soll, nicht! Mit anderen Worten,
ergibt -1 < 0u
. Warum ist das passiert? Ich kann das nicht erklären.
Beachten Sie, dass ich ähnliche Fragen wie this , aber sie helfen nicht.
PS. Wie @Abhineet sagte, kann das Dilemma gelöst werden, indem short
in int
geändert wird. Wie aber kann man dieses Phänomen erklären? Mit anderen Worten, -1
in 4 Bytes ist 0xff ff ff ff
und in 2 Bytes ist 0xff ff
. Wenn sie als 2s-Komplement angegeben werden, die als unsigned
interpretiert werden, haben sie entsprechende Werte von 4294967295
und 65535
. Sie beide sind nicht weniger als 0
und ich denke in beiden Fällen muss die Ausgabe -1 >= 0u
sein, d. H.% Co_de%.
Eine Beispielausgabe für ein kleines Endian-Intel-System:
Kurz gesagt:
%Vor%Für int:
%Vor%Der obige Code ergibt -1 & gt; = 0u
Alle Ganzzahl-Literale (numerische Konstanten) haben einen Typ und daher auch eine Signedness. Standardmäßig haben sie den Typ int
, der signiert ist. Wenn Sie das Suffix u
anhängen, wird das Literal in unsigned int
umgewandelt.
Für jeden C-Ausdruck, bei dem Sie einen signierten und einen ungesicherten Operanden haben, gilt die Regel des Wechsels (formal: die üblichen arithmetischen Konvertierungen ) konvertiert den signierten Typ implizit in unsigned.
Die Konvertierung von vorzeichenbehaftet nach vorzeichenlos ist wohldefiniert (6.3.1.3):
Wenn der neue Typ unsigniert ist, wird der Wert andernfalls durch wiederholtes Hinzufügen von oder konvertiert Subtrahieren von mehr als dem maximalen Wert, der in dem neuen Typ dargestellt werden kann bis der Wert im Bereich des neuen Typs ist.
Für 32-Bit-Ganzzahlen auf einem Standard-Zweierkomplement-System lautet der Maximalwert einer vorzeichenlosen Ganzzahl beispielsweise 2^32 - 1
(4294967295, UINT_MAX in limits.h). Ein mehr als der maximale Wert ist 2^32
. Und -1 + 2^32 = 4294967295
, daher wird das Literal -1
in einen unsigned int mit dem Wert 4294967295
konvertiert. Welches ist größer als 0.
Wenn Sie die Typen jedoch auf "short" setzen, erhalten Sie einen kleinen Integer-Typ . Dies ist der Unterschied zwischen den beiden Beispielen. Immer wenn ein kleiner Integer-Typ Teil eines Ausdrucks ist, konvertiert die Integer-Promotion-Regel diesen implizit in einen größeren int (6.3.1.1):
Wenn ein int alle Werte des Originaltyps darstellen kann (als eingeschränkt durch die Breite für ein Bitfeld) wird der Wert in ein int umgewandelt; Andernfalls wird es in einen unsigned int konvertiert. Diese heißen die ganzzahlige Werbeaktionen Alle anderen Typen sind unverändert durch die ganze Zahl Werbeaktionen.
Wenn short
auf der angegebenen Plattform kleiner ist als int
(wie bei 32- und 64-Bit-Systemen), wird jede short
oder unsigned short
daher immer in int
konvertiert, weil sie kann in einen passen.
Für den Ausdruck if (x < u)
haben Sie also tatsächlich if((int)x < (int)u)
, das sich wie erwartet verhält (-1 ist kleiner als 0).
Sie stoßen auf die C-Integer-Werberegeln.
Operatoren für Typen kleiner als int
stellen ihre Operanden automatisch auf int
oder unsigned int
hoch. Siehe Kommentare für detailliertere Erklärungen. Es gibt einen weiteren Schritt für binäre Operatoren (zwei Operanden), wenn die Typen danach immer noch nicht übereinstimmen (z.B. unsigned int vs. int). Ich werde nicht versuchen, die Regeln detaillierter zusammenzufassen. Siehe Lundins Antwort .
Dieser Blogbeitrag behandelt dies detaillierter, mit einem ähnlichen Beispiel deins: signed und unsigned char. Es zitiert die C99-Spezifikation:
Wenn ein int alle Werte des ursprünglichen Typs darstellen kann, lautet der Wert konvertiert zu einem int; Andernfalls wird es in einen unsigned int konvertiert. Diese werden als ganzzahlige Werbeaktionen bezeichnet. Alle anderen Arten sind unverändert durch die Integer-Promotions.
Sie können damit leichter auf etwas wie godbolt spielen, mit einer Funktion, die eins oder null zurückgibt . Sehen Sie sich die Compiler-Ausgabe an, um zu sehen, was passiert.
%Vor% Anders als Sie annehmen, ist dies keine Eigenschaft der speziellen Breite der Typen, hier 2 Byte gegenüber 4 Byte, sondern eine Frage der Regeln, die angewendet werden sollen. In den Regeln für ganzzahlige Werbung wird angegeben, dass short
und unsigned short
auf allen Plattformen, auf denen der entsprechende Wertebereich in int
passt, in int
konvertiert werden. Da dies der Fall ist, bleiben beide Werte erhalten und erhalten den Typ int
. -1
ist in int
perfekt darstellbar, wie auch in 0
. Die Testergebnisse in -1
sind also kleiner als 0
.
Wenn Sie -1
gegen 0u
testen, wählt die allgemeine Konvertierung den Typ unsigned
als einen gemeinsamen Typ, in den beide konvertiert werden. -1
konvertiert in unsigned
ist der Wert UINT_MAX
, der größer ist als 0u
.
Dies ist ein gutes Beispiel, warum Sie nie "schmale" Typen verwenden sollten, um Arithmetik oder Vergleich durchzuführen. Verwenden Sie sie nur, wenn Sie eine Servergrößenbeschränkung haben. Dies wird für einfache Variablen selten der Fall sein, aber meistens für große Arrays, bei denen Sie wirklich von einem Speichern in einem engen Typ profitieren können.
0u
ist nichtunsigned short
, es istunsigned int
.
Bearbeiten :: Die Erklärung für das Verhalten, Wie wird der Vergleich durchgeführt?
Wie von Jens Gustedt beantwortet,
Das nennt man "übliche arithmetische Konvertierungen" nach dem Standard und gilt immer dann, wenn zwei verschiedene Integer-Typen als Operanden des Typs auftreten derselbe Operator.
Im Wesentlichen was ist
wenn die Typen unterschiedliche Breite haben (genauer gesagt was der Standard ist ruft Conversion-Rang auf), dann konvertiert es in den breiteren Typ, wenn beides Typen haben die gleiche Breite, neben wirklich seltsamen Architekturen, die nicht signiert von ihnen gewinnt Signed zu unsigned Konvertierung des Wertes -1 mit welcher Art auch immer ergibt sich immer der höchste darstellbare Wert vom unsignierten Typ.
Der mehr erklärende Blog von ihm könnte hier
Tags und Links c bit-manipulation unsigned-integer integer-promotion twos-complement