Das Problem ist in Ihrem Vergleich:
%Vor% sizeof
gibt normalerweise unsigned long
zurück, so dass SIZE
unsigned long
ist, während -1
nur ein int
ist. Die Regeln für die Werbung in C und verwandten Sprachen bedeuten, dass -1 vor dem Vergleich in size_t
konvertiert wird, so dass -1
zu einem sehr großen positiven Wert wird (der Maximalwert von unsigned long
).
Eine Möglichkeit, dies zu beheben, besteht darin, den Vergleich zu ändern:
%Vor%obwohl es eigentlich ein sinnloser Vergleich ist, da ein vorzeichenloser Wert per Definition immer & gt; = 0 ist und der Compiler Sie wahrscheinlich davor warnen kann.
Wie Sie nachfolgend von @Nobilis notiert haben, sollten Sie immer Compilerwarnungen aktivieren und darauf achten: Wenn Sie mit z. gcc -Wall ...
Der Compiler hätte Sie vor Ihrem Fehler gewarnt.
Seien Sie vorsichtig mit gemischt signierten / unsignierten Operationen (benutzen Sie -Wall
Compiler Warnungen). Der Standard hat einen langen Abschnitt darüber. Insbesondere ist es oft, aber nicht immer richtig, dass signed in einen vorzeichenlosen Wert konvertiert wird (obwohl dies in Ihrem speziellen Beispiel der Fall ist). Siehe folgende Erklärung (aus diesem Q & A; )
5 Ausdrücke [expr]
10 Viele binäre Operatoren, die Operanden der Arithmetik oder erwarten Aufzählungstyp verursacht Konvertierungen und Ergebnistypen ähnlich Weg. Der Zweck ist es, einen gemeinsamen Typ zu ergeben, der auch die Art von ist das Ergebnis. Dieses Muster wird die üblichen arithmetischen Umwandlungen genannt, die wie folgt definiert sind:
[2 Klauseln über gleiche Typen oder Typen von Gleichheitszeichen entfallen]
- Andernfalls, wenn der Operand mit dem vorzeichenlosen Integer-Typ einen Rang hat größer oder gleich dem Rang des Typs des anderen Operanden, Der Operand mit dem Ganzzahl-Typ mit Vorzeichen muss in den Typ von konvertiert werden der Operand mit Vorzeichen ohne Vorzeichen.
- Andernfalls, wenn der Typ von Der Operand mit dem Ganzzahl-Typ mit Vorzeichen kann alle Werte darstellen vom Typ des Operanden mit vorzeichenloser Ganzzahl, der Operand mit vorzeichenlosen Integer Typ soll in den Typ der konvertiert werden Operand mit vorzeichenbehafteten Integer-Typ.
- Ansonsten sollen beide Operanden sein konvertiert in den vorzeichenlosen ganzzahligen Typ, der dem Typ von entspricht der Operand mit dem Ganzzahl-Typ mit Vorzeichen.
Um zu sehen, in welche der 3 Fälle Ihr Programm fällt, modifizieren Sie es leicht zu diesem
%Vor% Auf der Coliru Online-Compiler, das druckt 4 und 8 für das sizeof()
von -1
und SIZE
bzw. und wählt den "mehr" Zweig (live Beispiel ).
Der Grund dafür ist, dass der vorzeichenlose Typ einen höheren Rang als der signierte Typ hat. Daher gilt Klausel 1 und der vorzeichenbehaftete Typ wird in den vorzeichenlosen Typ wertkonvertiert (bei der meisten Implementation, typischerweise durch Beibehalten der Bitdarstellung, also Umwickeln mit einer sehr großen vorzeichenlosen Zahl), und der Vergleich fährt dann fort, um den " mehr "Zweig.
Umschreiben der Bedingung if ((long long)(-1) < (unsigned)SIZE)
würde die "weniger" Zweig ( Live-Beispiel ).
Der Grund dafür ist, dass der Typ mit Vorzeichen einen höheren Rang als der Typ ohne Vorzeichen hat und auch alle vorzeichenlosen Werte aufnehmen kann. Daher gilt Satz 2 und der vorzeichenlose Typ wird in den vorzeichenbehafteten Typ konvertiert, und der Vergleich fährt fort, um den "less" Zweig auszuwählen.
Natürlich würden Sie niemals eine so konstruierte if()
-Anweisung mit expliziten Umwandlungen schreiben, aber derselbe Effekt könnte auftreten, wenn Sie Variablen mit den Typen long long
und unsigned
vergleichen. Es veranschaulicht also den Punkt, dass gemischte vorzeichenbehaftete / vorzeichenlose Arithmetik sehr subtil ist und von den relativen Größen abhängt ("Ranking" in den Wörtern des Standards). Insbesondere gibt es keine Regeln, die besagen, dass signed immer in unsigned umgewandelt wird.
Wenn Sie das tun Vergleich zwischen signed
und unsigned
, wobei unsigned
mindestens ein gleichen Rang zu, dass der signed
Typ (TemplateRex Antwort für die genaue Regeln sehen), wird das signed
umgewandelt der Typ von unsigned
.
Im Hinblick auf Ihren Fall auf einer 32-Bit-Maschine die binäre Darstellung von -1
in unsigned
ist 4294967295. Also in der Tat Sie vergleichen, wenn 4294967295 kleiner als 8 (es ist nicht).
Wenn Sie Warnungen aktiviert hätten, wären Sie vom Compiler gewarnt worden, dass etwas faul ist:
warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
Da sich die Diskussion ein wenig verschoben hat, wie passend die Verwendung von unsigned
ist, lassen Sie mich ein Zitat von James Gosling in Bezug auf das Fehlen von unsigned
Typen in Java setzen (und ich werde schamlos link auf einem anderen Posten von mir zu diesem Thema):
Gosling: Für mich als Sprachdesigner, was ich nicht wirklich zähle ich selbst wie in diesen Tagen, was "einfach" wirklich am Ende Bedeutung war, konnte Ich erwarte, dass J. Random Developer die Spezifikation in seinem Kopf hält. Das Die Definition besagt, dass zum Beispiel Java nicht - und tatsächlich eine Menge davon ist Diese Sprachen enden mit einer Menge von Ecken Fällen, Dinge, die niemand versteht wirklich. Quiz alle C-Entwickler über unsigniert und hübsch Bald stellt sich heraus, dass fast keine C-Entwickler wirklich was verstehen geht mit unsigned weiter, was vorzeichenlose Arithmetik ist. Sachen wie diese machte C komplex. Der Sprachteil von Java ist, denke ich, ziemlich einfach. Die Bibliotheken müssen Sie nachschlagen.
Dies ist ein historischer Designfehler von C, der auch in C ++ wiederholt wurde.
Es geht auf 16-Bit-Computer zurück und der Fehler bestand darin, alle 16 Bits zu verwenden, um Größen von bis zu 65536 darzustellen, wodurch die Möglichkeit zur Darstellung negativer Größen aufgegeben wurde.
Dies wäre kein Fehler gewesen, wenn unsigned
bedeutung "nicht negative Ganzzahl" wäre (eine Größe kann logisch nicht negativ sein), aber es ist ein Problem mit den Konvertierungsregeln der Sprache.
Angesichts der Konvertierungsregeln der Sprache stellt der Typ unsigned
in C keine nicht negative Zahl dar, sondern eher eine Bitmaske (der mathematische Ausdruck ist eigentlich "ein Mitglied von ℤ/n
ring "). Um zu sehen, warum das für die C- und C ++ - Sprache in Betracht gezogen wird
unsigned - unsigned
gibt ein unsigned
result signed + unsigned
gibt und unsigned
result beide ergeben eindeutig keinen Sinn, wenn Sie unsigned
als "nicht negative Zahl" lesen.
Natürlich sagen, dass die Größe eines Objekts ein Mitglied von ℤ/n
Ring ist macht überhaupt keinen Sinn und hier ist es, wo der Fehler liegt.
Jedes Mal, wenn Sie mit der Größe eines Objekts arbeiten, seien Sie vorsichtig , da der Wert unsigned
ist und dieser Typ in C / C ++ viele Eigenschaften enthält, die für eine Zahl unlogisch sind. Bitte denken Sie immer daran, dass unsigned
nicht "nicht negative ganze Zahl" bedeutet, sondern "Mitglied von ℤ/n
algebraischen Ring" und dass am gefährlichsten ist, dass im Falle einer gemischten Operation int
in unsigned int
und konvertiert wird nicht das Gegenteil.
Zum Beispiel:
%Vor% ist fehlerhaft, denn wenn ein leerer Vektor von Punkten übergeben wird, werden ungültige (UB) Operationen ausgeführt. Der Grund ist, dass pts.size()
ein unsigned
ist.
Die Regeln der Sprache konvertieren 1
(eine Ganzzahl) in 1{mod n}
, führen die Subtraktion in ℤ/n
durch, was zu (size-1){mod n}
führt, konvertiert i
auch in eine {mod n}
Darstellung und wird Mach den Vergleich in ℤ/n
.
C / C ++ definiert tatsächlich einen <
Operator in ℤ/n
(selten in Mathe) und Sie werden am Ende auf pts[0]
, pts[1]
... usw. zugreifen, bis große Zahlen, selbst wenn der Eingabevektor war leer.
Eine korrekte Schleife könnte
sein %Vor%aber normalerweise bevorzuge ich
%Vor% Mit anderen Worten, wir werden unsigned
so schnell wie möglich los und arbeiten nur mit regulären Ints.
Verwenden Sie niemals unsigned
, um die Größe von Containern oder Zählern darzustellen, da unsigned
"Mitglied von ℤ/n
" bedeutet und die Größe eines Containers nicht eines dieser Dinge ist. Unsignierte Typen sind nützlich, aber NICHT , um die Größe von Objekten darzustellen.
Die Standard-C / C ++ - Bibliothek hat diese Auswahl leider falsch getroffen, und es ist zu spät, um sie zu beheben. Sie sind jedoch nicht gezwungen, denselben Fehler zu machen.
In den Worten von Bjarne Stroustrup :
Verwenden Sie ein unsigned statt eines int, um ein weiteres Bit zur Darstellung zu erhalten positive ganze Zahlen sind fast nie eine gute Idee. Versuche, das sicherzustellen Einige Werte sind positiv, indem Variablen ohne Vorzeichen deklariert werden in der Regel durch die impliziten Konvertierungsregeln besiegt werden
Nun, ich werde die starken Worte, die Paul R gesagt hat, nicht wiederholen, aber wenn du unsigned und ganze Zahlen vergleichst, wirst du schlechte Dinge erleben.
mach if ((-1) < (int)SIZE)
anstelle Ihrer if-Bedingung
Konvertiert den vorzeichenlosen Typ, der von sizeof operator zurückgegeben wurde, in signed
Wenn Sie zwei vorzeichenlose und vorzeichenbehaftete Zahlen vergleichen, wird der Compiler implizit in vorzeichenlos konvertiert.
-1 vorzeichenbehaftete Darstellung in 4 Byte int ist 11111111 11111111 11111111 11111111 Wenn diese in eine vorzeichenlose Darstellung umgewandelt wird, würde sich diese Darstellung auf 2 ^ 16-1 beziehen
Also im Grunde vergleichen Sie das 2 ^ 16-1 & gt; SIZE, was wahr wäre.
Sie müssen dies überschreiben, indem Sie den vorzeichenlosen Wert explizit in signed umwandeln.
Da sizeof operator unsigned long long zurückliefert, sollten Sie es auf signed long long
Verwenden Sie diese wenn Bedingung in Ihrem Code
Tags und Links c c++ comparison if-statement signed