2013-05-30 8 views
9

Ich habe einen Code, der Vergleich von 64-Bit-Ganzzahlen verwendet. Es sieht ähnlich wie die folgende:-Wesign-Vergleich Warnung in g ++

#include <cstdio> 

long long getResult() 
{ 
    return 123456LL; 
} 

int main() 
{ 
    long long result = getResult(); 

    if (result > 0x000FFFFFFFFFFFFFLL 
     || result < 0xFFF0000000000000LL) 
    { 
     printf("Something is wrong.\n"); 

     if (result > 0x000FFFFFFFFFFFFFLL 
      || result < -4503599627370496LL) 
     { 
      printf("Additional check failed too.\n"); 
     } 
     else 
     { 
      printf("Additional check went fine.\n"); 
     } 
    } 
    else 
    { 
     printf("Everything is fine.\n"); 
    } 

    return 0; 
} 

Wenn dieser Code in g kompiliert wird ++ (versucht, verschiedene Versionen auf Ubuntu 12.04 x64: 4.6.3, 4.6.4, 4.7.3, 4.8.0) mit Fahnen -Wall -pedantic -std = C++ 0x test.cpp -o Test, den ich für die zweite Zeile der ersten if-Anweisung -Wsign-Vergleich, Warnmeldungen angezeigt (Ausgabe von g ++ - 4.8):

test.cpp:13:17: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] 
|| result < 0xFFF0000000000000LL) 
      ^

Und wenn das Testprogramm läuft ich bekomme zwei Zeilen Text:

Something is wrong. 
Additional check went fine. 

Wenn für x86- oder x64-Architektur gleichen Code unter Windows mit MS Visual Studio 11 Express Update 2 mit Standardprojektoptionen Kompilieren ich nicht bekommen weder die Warnung noch diese Ausgabe, anstatt die Ausgabe:

Everything is fine. 

Ist es ein Problem im Code? Wenn ja, könnten Sie es zeigen? Oder ist es ein Problem mit dem verwendeten Compiler?

Das Hinzufügen einer zusätzlichen Typumwandlung für die zweite Konstante in der ersten if-Anweisung entfernt die Warnung in g ++.

+1

Das ist eine nette erste Frage, einschließlich eines vollständigen Beispiels und aller relevanten Informationen. –

+2

'0xFFF0000000000000', als ein positiver Wert, passt nicht lange in lange. Es passt jedoch in eine unsigned long long, also ist das der Typ, den gcc benutzt. –

+1

Das Suffix 'LL' kann verwendet werden, um den Compiler zu zwingen, einen längeren Typ zu wählen (' 1LL' ist lang lang), aber keinen kleineren Typ, für den Sie einen Cast wünschen ('(long long) 0xFFF0000000000000' (Genau genommen ist dies eine Implementierung definiert)). –

Antwort

10

Nach [lex.icon] in der Norm, der hexadezimale-wörtliche 0xFFF0000000000000LL hat unsigned long long eingeben, da der Wert in einem long long paßt nicht (Unsigned hexadecimal constant in C? und C interpretation of hexadecimal long integer literal "L" für weitere Informationen zu diesem Thema sehen.)

Das bedeutet, dass die Warnung von G ++ korrekt ist. Sie vergleichen long long result mit einem unsigned long long Literal.

Klar als ein vorzeichenloser Wert, 123456LL ist weniger als 0xFFF0000000000000LL, also ist auch das Ergebnis von G ++ korrekt.

MSVC scheint einen Fehler haben [Edit: oder verhält sich anders aus Kompatibilitätsgründen, siehe Kommentare], weil diese Behauptung nicht:

static_assert(0xFFF0000000000000LL > 0, "big number is big"); 

MSVC die wörtliche 0xFFF0000000000000LL Typ lange lange gibt, wie sie durch diese ungültig gezeigt Code, der von MSVC akzeptiert wird:

auto i = 0xFFF0000000000000LL; 
long long& l = i; 

A C++ 03 Beispiel, das ohne Fehler kompilieren sollte, ist:

template<typename T> 
void f(T t) 
{ 
    unsigned long long& l = t; 
} 

int main() 
{ 
    f(0xFFF0000000000000LL); 
} 

GCC, Clang, Intel und Solaris CC alle bekommen dieses Beispiel richtig, VC++ macht es falsch.

+0

+1 für die netten Möglichkeiten, den Fehler mit 'static_assert' und automatischem Typabzug zu validieren :) – legends2k

+0

Unterstützt VC++ 'long long' als C++ 11-Feature oder als C++ 03-Erweiterung? 'long long' war nicht Teil von C++ vor C++ 11, oder? – hvd

+0

Unter "-fms-extensions" von clang wird '0xFFF0000000000000LL' signiert. Ich glaube, das liegt daran, dass, wie @hvd angibt, VC++ vor C++ 11 "long long" hatte und dieses Verhalten für die Kompatibilität benötigt wird. – bames53