2010-06-23 40 views
17

Xét đoạn mã sau:Tại sao −1> sizeof (int)?

template<bool> class StaticAssert; 
template<> class StaticAssert<true> {}; 
StaticAssert< (-1 < sizeof(int)) > xyz1; // Compile error 
StaticAssert< (-1 > sizeof(int)) > xyz2; // OK 

Tại sao -1 > sizeof(int) đúng không?

  1. Có đúng là -1 được thăng cấp unsigned(-1) và sau đó unsigned(-1) > sizeof(int).
  2. Có đúng là -1 > sizeof(int) tương đương với -1 > size_t(4) nếu sizeof (int) là 4. Nếu đây là lý do tại sao -1 > size_t(4) là sai?

Đây có phải là chuẩn comformant C++ không?

Trả lời

14

Sau đây là cách tiêu chuẩn (ISO 14882) giải thích hủy bỏ -1> sizeof (int)

hành Relational `>' được định nghĩa trong 5.9 (expr.rel/2)

Chuyển đổi số học thông thường là được thực hiện trên toán hạng số học hoặc loại liệt kê. ...

Quá trình chuyển đổi số học thông thường được định nghĩa trong 5 (expr/9)

... Các mô hình được gọi là chuyển đổi số học thông thường, được định nghĩa như sau:

  • Nếu một trong hai toán hạng có loại dài đôi, ...
  • Nếu không, nếu toán hạng là dobule, ...
  • Nếu không, nếu toán hạng là nổi, ...
  • Nếu không, các quảng cáo tích phân sẽ được thực hiện trên cả hai toán hạng.
  • ...

Các chương trình khuyến mãi không thể thiếu được định nghĩa trong 4.5 (conv.prom/1)

Một rvalue kiểu char, ký char, unsigned char, short int, hoặc unsigned int ngắn có thể được chuyển đổi sang một rvalue kiểu int nếu int thể đại diện cho tất cả các giá trị của nguồn loại; nếu không, giá trị mã nguồn có thể là được chuyển đổi thành giá trị loại int chưa được ký.

Kết quả của sizeof được định nghĩa trong 5.3.3 (expr.sizeof/6)

Kết quả là một hằng số kiểu size_t

size_t được định nghĩa trong tiêu chuẩn C (ISO 9899), là loại số nguyên không dấu.

Vì vậy, đối với -1 > sizeof(int), trình kích hoạt> kích hoạt chuyển đổi số học thông thường. Chuyển đổi số học thông thường chuyển đổi -1 thành int không dấu vì int không thể biểu thị tất cả giá trị của size_t. -1 trở thành một số rất lớn phụ thuộc vào nền tảng. Vì vậy, -1 > sizeof(int)true.

+2

Nó chỉ có thể là một lỗi đánh máy nhưng 'size_t' là _an_ unsigned số nguyên và nó không phải là trường hợp' int' không thể đại diện cho tất cả các giá trị của 'size_t' (' size_t' có thể là 'unsigned short '), mặc dù nó rõ ràng là không thể trên nền tảng của người hỏi câu hỏi. –

+2

'(unsigned T) -1' không chỉ là một giá trị lớn, đó là * giá trị lớn nhất' unsigned T' có thể giữ. – GManNickG

+1

Tôi biết rõ tiêu chuẩn cho phép. :) -1 luôn là lớn nhất, đọc các quy tắc chuyển đổi. Hoặc http://stackoverflow.com/questions/809227/is-it-safe-to-use-1-to-set-all-bits-to-true/809341#809341 – GManNickG

14

Vì unsigned mạnh sau đó ký và -1 chuyển đổi sang giá trị unsigned như của size_t, vì vậy thực sự -1 == 0xFFFFFFFF > 4

Đây là cách nó nên làm việc theo chuẩn C++

+0

không biên dịch cảnh báo sự cố cho các trường hợp như vậy? – kriss

+0

điều này không giải thích tại sao -1 <(size_t) 4, sizeof nên sử dụng loại trả về size_t .. –

+0

@kriss - Các trình biên dịch khác nhau đưa ra các cảnh báo khác nhau. Các cảnh báo cũng có thể bị chặn lại thông qua các tùy chọn dòng lệnh của trình biên dịch, và/hoặc bởi các pragmas trong mã nguồn; và/hoặc sau đó có thể bị bỏ qua bởi lập trình viên. – ChrisW

4

vì -1 được đúc để size_t và đây là loại dữ liệu chưa được ký - vì vậy (size_t)-1 == 4294967295 (trên hệ thống 32 bit) chắc chắn lớn hơn 4

nếu bạn thêm -Wall vào cài đặt gcc chẳng hạn bạn nhận được cảnh báo rằng bạn so sánh một một dữ liệu unsigned ký và loại

+0

Có thực sự an toàn khi giả định rằng sizeof (size_t)> = sizeof (int) - IOW: nó có được chuẩn hóa không? – Wolf

2

Thật đơn giản và buồn. Trong C/C++:

  1. hầu hết thời gian, các loại unsigned integer có ngữ nghĩa của các số nguyên mô-đun (họ đại diện cho lớp tương đương)
  2. so sánh các loại unsigned integer có ngữ nghĩa của trật tự số nguyên thông thường, do đó 1U < 2U (IOW 0U là giá trị nhỏ nhất unsigned)
  3. sizeof có kiểu size_t
  4. size_t là một kiểu dữ liệu integer unsigned
  5. Point (1) ngụ ý rằng m ixed số học tính toán liên quan đến một ký và một số nguyên unsigned được thực hiện trong unsigned, mô-đun số học: đây là khả năng duy nhất mà không vi phạm "unsigned mean modular" quy tắc. Nó là tầm thường để chuyển đổi một số nguyên thành lớp tương đương của các số nguyên tương đương với nó. (Trong khi đi theo cách khác đòi hỏi sự lựa chọn của một số nguyên đại diện cho lớp tương đương.)
  6. Point (5) ngụ ý rằng -1 < 1U được hiểu như là unsigned(-1) < 1U, và unsigned(-1) = - 1U, và rõ ràng - 1U < 1U, vì vậy -1 < 1U là đúng.
  7. Điểm (1,3,4) ngụ ý rằng sizeof something hoạt động (chủ yếu) là một lớp tương đương (!!!).
  8. Tất cả điều này ngụ ý rằng -1 < sizeof something

Kết luận: đây là một lỗi thiết kế thừa hưởng từ C.

Rule:

Chỉ sử dụng các loại unsigned cho số học modula, bit thao tác (&, |, ^, <<, >>, ~ nhà khai thác), thao tác byte (unsigned char có nghĩa là "byte" trong C/C++) và các ký tự (unsigned char nghĩa là ký tự trong C/C++).

Không sử dụng các loại chưa ký để thực hiện số học.

Nếu hàm mong đợi giá trị số nguyên không được âm, hãy lấy số nguyên đã ký và tùy chọn kiểm tra hàm có giá trị nằm trong phạm vi.

+0

Tôi thấy điểm (6) hơi khó hiểu, có lẽ '==' được bao gồm trong * 'unsigned (-1)' = '- 1U' * sẽ tốt hơn – Wolf

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