2011-12-14 42 views
10

Mở Visual Studio 2010 chương trình sau đâyliterals số nguyên âm lớn

#include <iostream> 
using std::cout; 

int main() 
{ 
    cout << -2147483646 << '\n'; 
    cout << -2147483647 << '\n'; 
    cout << -2147483648 << '\n'; // numeric_limits<int>::min() 
    cout << -2147483649 << '\n'; 
    cout << -2147483650 << '\n'; 
    cout << "..." << '\n'; 
    cout << -4294967293 << '\n'; 
    cout << -4294967294 << '\n'; 
    cout << -4294967295 << '\n'; // -numeric_limits<unsigned int>::max() 
    cout << -4294967296 << '\n'; 
    cout << -4294967297 << '\n'; 
} 

tạo đầu ra sau đây

-2147483646 
-2147483647 
2147483648 
2147483647 
2147483646 
... 
3 
2 
1 
-4294967296 
-4294967297 

gì đang xảy ra?

Hành vi chuẩn này hoặc lỗi Visual Studio?

Chỉnh sửa: Như nhiều người đã chỉ ra, không có điều nào như số số nguyên âm. Xem câu trả lời tuyệt vời của Keith Thompson dưới đây để biết thêm chi tiết.

+0

Thú vị, đây là cách tháo gỡ: cout << -4294967293 << '\ n'; đẩy 0Ah mov esi, esp đẩy 3 Lưu ý rằng nó đẩy 3 ngay lập tức. (VS2010 cuối cùng) – ScarletAmaranth

+0

Nhà điều hành luồng của 'std :: cout' có lẽ không quảng cáo những chữ như bạn mong đợi. – AJG85

+0

@ScarletAmaranth Tôi nghĩ rằng đó là ok, bởi vì 4294967293 lần đầu tiên được đọc là int unsigned và hơn negated mà sản lượng 3. Không hoàn toàn chắc chắn mặc dù – hirschhornsalz

Trả lời

16

-2147483648 không phải là số nguyên; đó là một biểu thức gồm một toán tử - đơn nhất áp dụng cho chữ số 2147483648.

Trước tiêu chuẩn C++ 2011 mới, C++ không yêu cầu sự tồn tại của bất kỳ loại nào lớn hơn 32 bit (C++ 2011 thêm long long), vì vậy, 2147483648 là không thể di chuyển.

Một số nguyên thập phân đen là những người đầu tiên của các loại sau đây, trong đó giá trị của nó phù hợp:

int 
long int 
long long int (new in C++ 2011) 

Lưu ý rằng không bao giờ là của một loại unsigned trong tiêu chuẩn C++. Trong các phiên bản năm 1998 và 2003 của tiêu chuẩn C (không có long long int), một chữ số nguyên thập phân quá lớn để phù hợp với long int dẫn đến hành vi không xác định. Trong C++ 2011, nếu một số nguyên thập phân không phù hợp trong long long int, thì chương trình là "không đúng định dạng".

Nhưng gcc (ít nhất là bản phát hành 4.6.1, phiên bản mới nhất tôi có) không triển khai ngữ nghĩa C++ 2011. Các chữ số 2147483648, không phù hợp với độ dài 32 bit, được coi là unsigned long, ít nhất là trên hệ thống 32 bit của tôi. (Đó là tốt cho C++ 98 hoặc C++ 2003, hành vi là không xác định, do đó, trình biên dịch có thể làm bất cứ điều gì nó thích.)

Vì vậy, cho một điển hình 32-bit 2's-bổ sung int loại, này:

cout << -2147483647 << '\n'; 

lấy int giá trị 2147483647, phủ nhận nó, và in kết quả, mà phù hợp với kết quả toán học mà bạn mong đợi . Nhưng điều này:

cout << -2147483648 << '\n'; 

(khi biên dịch với gcc 4.6.1) lấy long hoặc unsigned long giá trị 2147483648, phủ nhận nó như một unsigned int, năng suất 2147483648, và in đó.

Như những người khác đã đề cập, bạn có thể sử dụng hậu tố để buộc một loại cụ thể.

Dưới đây là một chương trình nhỏ mà bạn có thể sử dụng để hiển thị như thế nào xử lý biên dịch của bạn literals:

#include <iostream> 
#include <climits> 

const char *type_of(int)    { return "int"; } 
const char *type_of(unsigned int)  { return "unsigned int"; } 
const char *type_of(long)    { return "long"; } 
const char *type_of(unsigned long)  { return "unsigned long"; } 
const char *type_of(long long)   { return "long long"; } 
const char *type_of(unsigned long long) { return "unsigned long long"; } 

int main() 
{ 
    std::cout << "int: " << INT_MIN << " .. " << INT_MAX << "\n"; 
    std::cout << "long: " << LONG_MIN << " .. " << LONG_MAX << "\n"; 
    std::cout << "long long: " << LLONG_MIN << " .. " << LLONG_MAX << "\n"; 

    std::cout << "2147483647 is of type " << type_of(2147483647) << "\n"; 
    std::cout << "2147483648 is of type " << type_of(2147483648) << "\n"; 
    std::cout << "-2147483647 is of type " << type_of(-2147483647) << "\n"; 
    std::cout << "-2147483648 is of type " << type_of(-2147483648) << "\n"; 
} 

Khi tôi biên dịch nó, tôi nhận được một số cảnh báo:

lits.cpp:18:5: warning: this decimal constant is unsigned only in ISO C90 
lits.cpp:20:5: warning: this decimal constant is unsigned only in ISO C90 

và đầu ra sau, thậm chí với gcc -std=c++0x:

int: -2147483648 .. 2147483647 
long: -2147483648 .. 2147483647 
long long: -9223372036854775808 .. 9223372036854775807 
2147483647 is of type int 
2147483648 is of type unsigned long 
-2147483647 is of type int 
-2147483648 is of type unsigned long 

Tôi nhận được kết quả tương tự với VS2010, ít nhất với defau lt cài đặt.

+2

Nhưng, như bạn vừa giải thích, một chữ số nguyên là không bao giờ unsigned. 2147483648 phải có loại 'long long' ở đây. –

+0

@Keith: Bạn đang mâu thuẫn với chính mình: "Lưu ý rằng nó không bao giờ là một loại không dấu" và "lấy giá trị int unsigned 2147483648". Ông có thể làm rõ? – user763305

+1

OOPS! Tôi sẽ sửa chữa nó. –

2

Khi tôi biên dịch này trong GCC, tôi nhận được thông báo sau:

warning: this decimal constant is unsigned only in ISO C90 [enabled by default] 

Nó xảy ra cho tất cả các dòng sau (và bao gồm)

cout << -2147483648 << '\n'; // numeric_limits<int>::min() 

Vì vậy, những gì đang xảy ra là trình biên dịch cả Visual Studio và GCC cho phép chúng tôi viết những chữ này, và họ chỉ đối xử với họ như thể đã được đánh dấu là chưa ký. Điều này giải thích hành vi của những gì được in, và nó làm cho tôi khá tự tin rằng đầu ra là chính xác (giả sử chúng tôi đã đặt một hậu tố u trên các con số).

Tôi vẫn thấy thú vị là -2147483648 không phải là một số nguyên có chữ ký hợp lệ, mặc dù đó là giá trị số nguyên có dấu hợp lệ. Có ai nghĩ về điều đó không? Ví dụ:

+3

'-2147483648' không phải là một chữ số nguyên có chữ ký nào cả. '2147483648' là một chữ số nguyên (hằng số, thực sự), và' -' là toán tử trừ đơn nhất. –

+0

Có thể vì nó được đọc là '2147483648', chỉ tồn tại dưới dạng unsigned, và sau đó phủ nhận. – hirschhornsalz

+0

@ James: Cảm ơn vì không. Tôi không biết rằng '-' không phải là một phần của chữ số –

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