Ich versuche zu verstehen, warum der folgende Code an der angegebenen Stelle keine Warnung ausgibt.
//from limits.h
#define UINT_MAX 0xffffffff /* maximum unsigned int value */
#define INT_MAX 2147483647 /* maximum (signed) int value */
/* = 0x7fffffff */
int a = INT_MAX;
//_int64 a = INT_MAX; // makes all warnings go away
unsigned int b = UINT_MAX;
bool c = false;
if(a < b) // warning C4018: '<' : signed/unsigned mismatch
c = true;
if(a > b) // warning C4018: '<' : signed/unsigned mismatch
c = true;
if(a <= b) // warning C4018: '<' : signed/unsigned mismatch
c = true;
if(a >= b) // warning C4018: '<' : signed/unsigned mismatch
c = true;
if(a == b) // no warning <--- warning expected here
c = true;
if(((unsigned int)a) == b) // no warning (as expected)
c = true;
if(a == ((int)b)) // no warning (as expected)
c = true;
Ich dachte, es hätte mit Hintergrundwerbung zu tun, aber die letzten beiden scheinen etwas anderes zu sagen.
Meiner Meinung nach ist der erste ==
Vergleich genauso eine signierte / nicht signierte Nichtübereinstimmung wie die anderen?
-1
funktionieren Ihre Vergleiche mit bare weiterhin (aber diese geben eine Warnung), während Ihre Vergleiche mit-1u
oder(unsigned)-1
beide kläglich fehlschlagen.Antworten:
Beim Vergleich von vorzeichenbehafteten mit vorzeichenlosen Werten konvertiert der Compiler den vorzeichenbehafteten Wert in vorzeichenlosen Wert. Für die Gleichstellung spielt dies keine Rolle
-1 == (unsigned) -1
. Für andere Vergleiche ist es wichtig, zB gilt :-1 > 2U
.EDIT: Referenzen:
5/9: (Ausdrücke)
4.7 / 2: (Integrale Konvertierungen)
EDIT2: MSVC-Warnstufen
Was bei den verschiedenen Warnstufen von MSVC gewarnt wird, sind natürlich die Entscheidungen der Entwickler. Aus meiner Sicht sind ihre Entscheidungen in Bezug auf signierte / nicht signierte Gleichheit im Vergleich zu größeren / weniger Vergleichen sinnvoll. Dies ist natürlich völlig subjektiv:
-1 == -1
bedeutet das gleiche wie-1 == (unsigned) -1
- ich finde das ein intuitives Ergebnis.-1 < 2
bedeutet nicht dasselbe wie-1 < (unsigned) 2
- Dies ist auf den ersten Blick weniger intuitiv und IMO verdient eine "frühere" Warnung.quelle
(unsigned)-1
oder-1u
oft schlechter als der Vergleich mit-1
. Das liegt daran(unsigned __int64)-1 == -1
, aber(unsigned __int64)-1 != (unsigned)-1
. Wenn der Compiler also eine Warnung ausgibt, versuchen Sie, diese durch Umwandlung in unsigned oder using zum Schweigen zu bringen.-1u
Wenn der Wert tatsächlich 64-Bit ist oder Sie ihn später in einen ändern, wird Ihr Code beschädigt! Und denken Sie daran, dasssize_t
64-Bit ohne Vorzeichen nur auf 64-Bit-Plattformen verwendet wird und die Verwendung von -1 für ungültige Werte sehr häufig ist.Warum signierte / nicht signierte Warnungen wichtig sind und Programmierer sie beachten müssen, zeigt das folgende Beispiel.
Erraten Sie die Ausgabe dieses Codes?
Ausgabe:
Überrascht? Online-Demo: http://www.ideone.com/5iCxY
Fazit: Wenn im Vergleich ein Operand ist
unsigned
, wird der andere Operand implizit in konvertiert,unsigned
wenn sein Typ signiert ist!quelle
i<0
. Danni
ist kleiner alsj
sicher. Wenni
es nicht kleiner als Null ist,ì
kann es sicher in vorzeichenloses konvertiert werden, um es mit zu vergleichenj
. Sicher, Vergleiche zwischen signierten und nicht signierten wären langsamer, aber ihr Ergebnis wäre in gewissem Sinne korrekter.Der Operator == führt nur einen bitweisen Vergleich durch (durch einfache Division, um festzustellen, ob er 0 ist).
Die kleineren / größeren als Vergleiche hängen viel mehr vom Vorzeichen der Zahl ab.
4 Bit Beispiel:
1111 = 15? oder -1?
Wenn Sie also 1111 <0001 haben ... ist es mehrdeutig ...
aber wenn Sie 1111 == 1111 haben ... Es ist das gleiche, obwohl Sie es nicht so gemeint haben.
quelle
In einem System, das die Werte mit 2-Komplementen darstellt (modernste Prozessoren), sind sie auch in ihrer binären Form gleich. Dies kann der Grund sein, warum sich der Compiler nicht über a == b beschwert .
Und für mich ist es ein seltsamer Compiler, der Sie nicht vor a == ((int) b) warnt . Ich denke, es sollte Ihnen eine Ganzzahl-Kürzungswarnung oder so geben.
quelle
Die betreffende Codezeile generiert keine C4018-Warnung, da Microsoft eine andere Warnnummer (z. B. C4389 ) verwendet hat, um diesen Fall zu behandeln, und C4389 standardmäßig nicht aktiviert ist (dh auf Stufe 3).
Aus den Microsoft-Dokumenten für C4389:
Die anderen Antworten haben recht gut erklärt, warum Microsoft möglicherweise beschlossen hat, aus dem Gleichheitsoperator einen Sonderfall zu machen, aber ich finde, dass diese Antworten nicht besonders hilfreich sind, ohne C4389 zu erwähnen oder wie man es in Visual Studio aktiviert .
Ich sollte auch erwähnen, dass Sie, wenn Sie C4389 aktivieren möchten, möglicherweise auch die Aktivierung von C4388 in Betracht ziehen. Leider gibt es keine offizielle Dokumentation für C4388, aber es scheint in Ausdrücken wie den folgenden aufzutauchen:
quelle