2013-05-30 3 views
9

私は64ビット整数の比較を使用するコードを持っています。それは次のようになります-g ++のWsign-compare警告

#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; 
} 

このコードはGでコンパイルされると++(Ubuntuの12.04 x64で異なるバージョンを試してみました:4.6.3、4.6.4、4.7.3、4.8.0)のフラグを-Wall -pedantic -std = C++ 0xのTEST.CPP -oテスト私は-Wsign-比較すると、最初のステートメント(G ++からの出力 - 4.8)の2行目のための警告を得る:

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

そして、テストプログラム私は2行のテキストを得る:

Something is wrong. 
Additional check went fine. 

x86またはx64アーキテクチャのいずれかのデフォルトのプロジェクトオプションでMSのVisual Studio 11 Expressのアップデート2を使用してWindows上で同じコードをコンパイルするとき、私は警告も、この出力どちらを得ることはありません、代わりに出力されている:

Everything is fine. 

されていますそれはコードの問題ですか?はいの場合は、それを指摘できますか?それとも、コンパイラに問題がありますか?

最初のifステートメントで2番目の定数の型キャストを追加すると、g ++で警告が削除されます。標準で[lex.icon]によれば、16進リテラル0xFFF0000000000000LL値がlong longに収まらないので、unsigned long long型を持つ

+1

これは素晴らしい例です。完全な例と関連するすべての情報が含まれています。 –

+2

「0xFFF0000000000000」は正の値としてlong longに収まりません。しかし、それはunsigned long longに収まるので、gccが使用する型です。 –

+1

拡張子 'LL'はコンパイラに長い型(' 1LL'はlong long)を選択させますが、より小さい型は選択しないようにするために使用できます。 '(long long)0xFFF0000000000000'(厳密に言えば、これは定義された実装です))。 –

答えて

10

(これについての詳細はUnsigned hexadecimal constant in C?C interpretation of hexadecimal long integer literal "L"を参照。)

これは、G ++の警告が正しいことを意味します。long long resultunsigned long longのリテラルを比較しています。

明らかに符号なしの値として、123456LL0xFFF0000000000000LLより小さいので、G ++の結果も正しいです。

MSVCにバグがあるようです:このアサーションが失敗したので、[編集]をやコメントを参照して、互換性の理由のために動作が異なります]:この無効で示すように

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

MSVCは、長い長いリテラル0xFFF0000000000000LLタイプを提供しますMSVCによって受け入れられるコード:

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

C++ 03の例エラーなくコンパイルする必要があります:

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

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

GCC、Clang、Intel、およびSolaris CCはすべてこの例を正しく取得しています。

+0

'static_assert'と自動型減算を使ってバグを検証する良い方法は+1 – legends2k

+0

VC++は' long long'をC++ 11の機能として、あるいはC++ 03の拡張機能としてサポートしていますか? 'long long'はC++ 11の前に標準C++の一部ではありませんでしたか? – hvd

+0

clangの '-fms-extensions'フラグの下で、' 0xFFF0000000000000LL'が署名されます。これは、@ hvdが示すように、VC++はC++ 11より前に 'long long'を持っていたため、この動作は互換性のために必要であると考えています。 – bames53