9

64 ビット整数の比較を使用するコードがあります。次のようになります。

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

このコードがフラグ -Wall -pedantic -std=c++0x test.cpp -o を使用して g++ でコンパイルされた場合 (Ubuntu 12.04 x64 で異なるバージョンを試した場合: 4.6.3、4.6.4、4.7.3、4.8.0)最初の if ステートメントの 2 行目に -Wsign-compare 警告が表示されます (g++-4.8 からの出力):

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

テスト プログラムを実行すると、次の 2 行のテキストが表示されます。

Something is wrong.
Additional check went fine.

MS Visual Studio 11 Express Update 2 を使用して、x86 または x64 アーキテクチャの既定のプロジェクト オプションを使用して Windows で同じコードをコンパイルすると、警告もこの出力も表示されません。代わりに、出力は次のようになります。

Everything is fine.

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

最初の if ステートメントの 2 番目の定数に追加の型キャストを追加すると、g++ の警告が削除されます。

4

1 に答える 1

11

標準の [lex.icon] によると、値が a に収まらないため、 16 進数リテラル0xFFF0000000000000LLは typeを持ちます(詳細については、C の符号なし 16 進定数?および16 進長整数リテラル "L" の C 解釈を参照してください)。これ。)unsigned long longlong long

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

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

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

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

MSVC で受け入れられる次の無効なコードが示すように、MSVC はリテラル0xFFF0000000000000LL型 long long を指定します。

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 はすべてこの例を正しく理解していますが、VC++ は間違っています。

于 2013-05-30T12:59:59.653 に答える