2013-05-30 25 views
9

Tôi có mã sử dụng so sánh các số nguyên 64 bit. Nó trông tương tự như sau:Cảnh báo so sánh hiệu chỉnh trong 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; 
} 

Khi mã này được biên soạn trong g ++ (thử phiên bản khác nhau trên Ubuntu 12.04 x64: 4.6.3, 4.6.4, 4.7.3, 4.8.0) với cờ Wall -pedantic -std = C++ 0x test.cpp -o thử nghiệm tôi nhận được -Wsign-so sánh cảnh báo cho dòng thứ hai của người đầu tiên câu lệnh if (đầu ra từ g ++ - 4.8):

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

Và khi chương trình thử nghiệm được chạy Tôi nhận được hai dòng văn bản:

Something is wrong. 
Additional check went fine. 

Khi biên dịch cùng một mã trên Windows sử dụng MS Visual Studio 11 Express Cập nhật 2 với các tùy chọn mặc định dự án cho một trong hai x86 hoặc x64 kiến ​​trúc Tôi không nhận được không phải cảnh báo cũng không ra này, thay vì đầu ra là:

Everything is fine. 

Is nó là một vấn đề trong mã? Nếu có, bạn có thể chỉ ra nó? Hoặc nó là một vấn đề với trình biên dịch được sử dụng?

Thêm phép loại bổ sung cho hằng số thứ hai trong câu lệnh if đầu tiên sẽ xóa cảnh báo trong g ++.

+1

Đó là một câu hỏi hay, bao gồm một ví dụ hoàn chỉnh và tất cả các thông tin liên quan. –

+2

'0xFFF0000000000000', dưới dạng giá trị dương, không vừa trong thời gian dài. Tuy nhiên, nó phù hợp trong một unsigned dài lâu, do đó, đó là loại gcc sử dụng. –

+1

Hậu tố 'LL' có thể được sử dụng để buộc trình biên dịch chọn loại dài hơn (' 1LL' dài), nhưng không chọn loại nhỏ hơn, bạn muốn một dàn diễn viên ('long long) 0xFFF0000000000000' (nghiêm chỉnh nói điều này được thực hiện xác định)). –

Trả lời

10

Theo [lex.icon] trong tiêu chuẩn, các hệ thập lục phân-đen 0xFFF0000000000000LL đã gõ unsigned long long, vì giá trị không phù hợp trong một long long (xem Unsigned hexadecimal constant in C?C interpretation of hexadecimal long integer literal "L" để biết thêm thông tin về vấn đề này.)

Điều này có nghĩa là cảnh báo của G ++ là chính xác, bạn đang so sánh long long result với một chữ cái unsigned long long.

Rõ ràng là giá trị chưa ký, 123456LL nhỏ hơn 0xFFF0000000000000LL, do đó kết quả của G ++ cũng chính xác.

MSVC dường như có một lỗi [Edit: hoặc cư xử khác nhau vì những lý do tương thích, xem ý kiến], bởi vì sự khẳng định này không thành công:

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

MSVC cung cấp cho các literal 0xFFF0000000000000LL loại dài dài, như thể hiện bởi không hợp lệ này mã mà được chấp nhận bởi MSVC:

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

Một C++ 03 ví dụ mà nên biên dịch mà không có lỗi là:

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

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

GCC, Clang, Intel và Solaris CC đều nhận được ví dụ này đúng, VC++ đã sai.

+0

+1 cho những cách tốt nhất để xác nhận lỗi bằng cách sử dụng 'static_assert' và tự động loại trừ :) – legends2k

+0

VC++ có hỗ trợ' long long' như một tính năng C++ 11 hay là phần mở rộng C++ 03 không? 'long long' không phải là một phần của tiêu chuẩn C++ trước C++ 11, phải không? – hvd

+0

Dưới cờ '-fms-extensions' của 'clang'' 0xFFF0000000000000LL' sẽ được ký. Tôi tin rằng điều này là bởi vì, như @hvd chỉ ra, VC++ có 'long long' trước C++ 11 và hành vi này là cần thiết để tương thích. – bames53

Các vấn đề liên quan