2013-05-30 70 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

相關問題