2013-05-30 71 views
9

我有一个使用64位整数比较的代码。它类似于以下内容:-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; 
} 

当该代码在编译克++(试图在Ubuntu 12.04不同版本的x64:4.6.3,4.6.4,4.7.3,4.8.0)用旗-Wall -pedantic -std =的C++ 0x TEST.CPP -o测试I得到-Wsign - 比较用于(从克++输出 - 4.8)第一if语句的第二行警告:

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

而当测试程序运行我得到两行文字:

Something is wrong. 
Additional check went fine. 

在使用MS的Visual Studio 11 Express中更新2与x86或x64架构我不明白既不报警也不该输出默认项目选项在Windows编译相同的代码,而不是输出为:

Everything is fine. 

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

在第一个if语句中为第二个常量添加其他类型转换,从而删除g ++中的警告。

+1

这是一个很好的第一个问题,包括一个完整的例子和所有相关信息。 –

+2

'0xFFF0000000000000'作为一个正值,不适合很长时间。但是,它适合于一个无符号long long,所以这是gcc使用的类型。 –

+1

后缀'LL'可以用来强制编译器选择一个更长的类型('1LL'很长),但不是选择一个较小的类型,而是希望对该类型进行强制转换('(long long)0xFFF0000000000000'(严格来说这是实现定义的))。 –

回答

10

根据[lex.icon]在标准中,十六进制文字0xFFF0000000000000LL已键入unsigned long long,因为该值不以long long适合(参见Unsigned hexadecimal constant in C?C interpretation of hexadecimal long integer literal "L"的更多信息,这一点。)

这意味着G ++的警告是正确的,您将long long resultunsigned long long文字进行比较。

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

MSVC似乎有一个bug [编辑:或行为有所不同兼容性的原因,看评论],因为这种断言失败:

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

MSVC给人的字面0xFFF0000000000000LL long long类型,见下面的无效由MSVC接受代码:

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

A C++ 03的例子,应该编译没有错误是:

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

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

GCC,Clang,Intel和Solaris CC都正确地得到了这个例子,VC++弄错了。

+0

+ 1为使用'static_assert'和自动类型演绎验证错误的好方法:) – 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

相关问题