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

当此代码在 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-compare 第一个 if 语句第二行的警告(从 g++-4.8 输出):

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

当测试程序运行时,我得到两行文本:

Something is wrong.
Additional check went fine.

在 Windows 上使用 MS Visual Studio 11 Express Update 2 和 x86 或 x64 架构的默认项目选项编译相同的代码时,我既没有收到警告也没有收到此输出,而是输出:

Everything is fine.

是不是代码有问题?如果是的话,你能指出来吗?还是使用的编译器有问题?

在第一个 if 语句中为第二个常量添加额外的类型转换会删除 g++ 中的警告。

4

1 回答 1

11

根据标准中的 [lex.icon],hexadecimal-literal0xFFF0000000000000LL具有 type unsigned long long,因为该值不适合 a long long(请参阅Unsigned hexadecimal constant in C?十六进制长整数文字“L”的 C 解释了解更多信息)这。)

这意味着 G++ 的警告是正确的,您正在与long long result文字unsigned long long进行比较。

显然,作为一个无符号值,123456LL小于0xFFF0000000000000LL,所以 G++ 的结果也是正确的。

MSVC 似乎有一个错误 [编辑:或出于兼容性原因表现不同,请参阅评论],因为此断言失败:

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

MSVC 给出了字面0xFFF0000000000000LL量类型 long long,正如 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 都正确地理解了这个示例,VC++ 错误地理解了它。

于 2013-05-30T12:59:59.653 回答