2008-10-01 39 views
92

Có phải C++ enums đã ký hoặc chưa ký? Và bằng cách mở rộng là nó an toàn để xác nhận một đầu vào bằng cách kiểm tra rằng nó là < = giá trị tối đa của bạn, và để lại> = giá trị min của bạn (giả sử bạn bắt đầu ở 0 và tăng lên 1)?Có phải C++ enums đã ký hoặc chưa ký?

+0

Khi chúng tôi đang sử dụng một kiểu enum trong một bối cảnh đó đòi hỏi các dấu hiệu của nó, chúng tôi đang thực sự nói về chuyển đổi enum để một kiểu không thể thiếu ngầm. Tiêu chuẩn C++ 03 cho biết điều này được thực hiện bằng cách tích hợp Khuyến mãi, không có gì liên quan đến kiểu cơ bản của enum. Vì vậy, tôi không hiểu tại sao mọi câu trả lời ở đây đề cập đến loại cơ bản không được định nghĩa theo tiêu chuẩn? Tôi mô tả các hành vi mong đợi ở đây: http://stackoverflow.com/questions/24802322/sign-of-c-enum-type-incorrect-after-converting-to-integral-type – JavaMan

Trả lời

56

Bạn không nên dựa vào bất kỳ đại diện cụ thể nào. Đọc phần sau đây link. Ngoài ra, tiêu chuẩn nói rằng nó được thực hiện xác định loại tích phân được sử dụng làm kiểu cơ bản cho một enum, ngoại trừ nó không được lớn hơn int, trừ khi một số giá trị không thể khớp với int hoặc int không dấu.

Tóm lại: bạn không thể dựa vào một enum được ký hoặc không ký.

+21

[Câu trả lời của Michael Burr] (http://stackoverflow.com/a/159308/594137) (trích dẫn tiêu chuẩn) thực sự ngụ ý bạn * có thể * dựa vào nó được ký nếu bạn xác định giá trị enum là âm do loại có thể "đại diện cho tất cả giá trị của điều tra được xác định trong điều tra ". –

4

Trình biên dịch có thể quyết định có hoặc không có enums được ký hoặc chưa ký.

Một phương pháp xác thực khác là sử dụng enum như một loại biến. Ví dụ:

enum Fruit 
{ 
    Apple = 0, 
    Banana, 
    Pineapple, 
    Orange, 
    Kumquat 
}; 

enum Fruit fruitVariable = Banana; // Okay, Banana is a member of the Fruit enum 
fruitVariable = 1; // Error, 1 is not a member of enum Fruit even though it has the same value as banana. 
19

Bạn không nên phụ thuộc vào chúng được ký hoặc chưa ký. Nếu bạn muốn làm cho họ một cách rõ ràng ký kết hoặc unsigned, bạn có thể sử dụng như sau:

enum X : signed int { ... }; // signed enum 
enum Y : unsigned int { ... }; // unsigned enum 
+10

Chỉ trong tiêu chuẩn C++ 0x trong tương lai. – dalle

+3

@dalle Microsoft compilator cũng cho phép gõ enums http://msdn.microsoft.com/en-us/library/2dzy4k6e(v=vs.80).aspx – teodozjan

3

Trong tương lai, với C++ 0x, strongly typed enumerations sẽ có sẵn và có nhiều lợi thế (chẳng hạn như loại an toàn, rõ ràng các loại cơ bản hoặc phạm vi rõ ràng). Với điều đó bạn có thể được đảm bảo tốt hơn về các dấu hiệu của loại.

95

Hãy chuyển đến nguồn. Đây là những gì tiêu chuẩn C++ 03 (ISO/IEC 14882: 2003) tài liệu nói trong 7,2-5 (tờ khai Enumeration):

Các loại cơ bản của một điều tra là một loại không thể thiếu mà có thể đại diện cho tất cả các giá trị điều tra được xác định trong điều tra. Đó là thực hiện xác định mà không thể thiếu loại được sử dụng như các loại cơ bản cho một điều tra ngoại trừ việc loại cơ bản sẽ không được lớn hơn int trừ khi giá trị của một Enumerator không thể phù hợp trong một int hoặc int unsigned.

Tóm lại, trình biên dịch của bạn phải chọn (rõ ràng, nếu bạn có số âm cho một số giá trị đếm của bạn, nó sẽ được ký).

+0

Làm thế nào chúng ta có thể tránh trình biên dịch đoán và nói với nó để sử dụng một cơ sở loại unsigned khi tất cả các giá trị đếm là nhỏ, số nguyên dương? (Chúng tôi đang bắt một phát hiện UBsan bởi vì trình biên dịch được chọn một int, và tràn tràn của int. Giá trị là unsigned và tích cực, và sử dụng của chúng tôi phụ thuộc vào unsigned bọc để cung cấp một decrement hoặc "stride tiêu cực"). – jww

+0

@ jww - điều đó sẽ phụ thuộc vào trình biên dịch chính xác mà bạn đang sử dụng, tôi đoán vậy. Vì tiêu chuẩn không quy định loại cơ bản, và để điều này thực hiện, sau đó cần xem tài liệu của công cụ của bạn và xem liệu tùy chọn này có khả thi hay không. Nếu bạn muốn đảm bảo một hành vi nhất định trong mã của mình, tại sao không truyền thành viên enum mà bạn sử dụng trong biểu thức? – ysap

12

Bạn không nên dựa vào đó là đã ký hoặc chưa ký. Theo tiêu chuẩn, nó được thực hiện xác định loại tích phân nào được sử dụng làm kiểu cơ bản cho một enum. Trong hầu hết các triển khai, mặc dù, nó là một số nguyên đã ký.

Trong C++ 0x strongly typed enumerations sẽ được bổ sung mà sẽ cho phép bạn chỉ định kiểu của một enum như:

enum X : signed int { ... }; // signed enum 
enum Y : unsigned int { ... }; // unsigned enum 

Ngay cả bây giờ, tuy nhiên, một số xác nhận đơn giản có thể đạt được bằng cách sử dụng enum như một loại biến hay tham số như thế này:

enum Fruit { Apple, Banana }; 

enum Fruit fruitVariable = Banana; // Okay, Banana is a member of the Fruit enum 
fruitVariable = 1; // Error, 1 is not a member of enum Fruit 
        // even though it has the same value as banana. 
+0

Tôi nghĩ rằng ví dụ thứ hai của bạn là một chút bối rối :) – Miral

3

Ngoài những gì người khác đã nói về ký/unsigned, đây là những gì tiêu chuẩn nói về phạm vi của một kiểu liệt kê:

7.2 (6): "Đối với một điều tra trong đó e (min) là điều tra nhỏ nhất và e (max) là lớn nhất, các giá trị của liệt kê là các giá trị của kiểu cơ bản trong phạm vi b (min) đến b (max), trong đó b (min) và b (max) là các giá trị nhỏ nhất và lớn nhất của bitfield nhỏ nhất có thể lưu e (min) và e (max). Nó có thể xác định một điều tra có giá trị không xác định bởi bất kỳ điều tra viên của mình "

Vì vậy, ví dụ:.

enum { A = 1, B = 4}; 

định nghĩa một kiểu liệt kê trong đó e (min) là 1 và e (max) là 4. Nếu kiểu cơ bản là int, thì bitfield nhỏ nhất được yêu cầu có 4 bit, và nếu ints trong thực hiện của bạn là phần bù của hai thì phạm vi hợp lệ của enum là -8 đến 7. Nếu kiểu cơ bản là unsigned, thì nó có 3 bit và phạm vi là từ 0 đến 7. Kiểm tra tài liệu biên dịch của bạn nếu bạn quan tâm (ví dụ nếu bạn muốn truyền các giá trị tích phân khác với số đếm vào kiểu liệt kê, thì bạn cần phải biết liệu giá trị có nằm trong phạm vi điều tra hay không - nếu không phải là giá trị enum kết quả là không xác định).

Cho dù các giá trị đó là đầu vào hợp lệ cho hàm của bạn có thể là một vấn đề khác với việc chúng có phải là giá trị hợp lệ của loại được liệt kê hay không. Mã kiểm tra của bạn có lẽ là lo lắng về cái cũ hơn là cái thứ hai, và vì vậy trong ví dụ này ít nhất nên kiểm tra> = A và < = B.

4

Thậm chí một số câu trả lời cũ có 44 phiếu bầu, tôi có xu hướng không đồng ý với tất cả chúng. Trong ngắn hạn, tôi không nghĩ rằng chúng ta nên quan tâm đến các underlying type của enum.

Trước hết, C++ 03 Loại enum là một loại riêng biệt của riêng nó không có khái niệm về dấu. Kể từ khi từ C++ 03 tiêu chuẩn dcl.enum

7.2 Enumeration declarations 
5 Each enumeration defines a type that is different from all other types.... 

Vì vậy, khi chúng ta đang nói về những dấu hiệu của một kiểu enum, nói khi so sánh 2 toán hạng enum sử dụng toán tử <, chúng tôi đang thực sự nói về ngầm chuyển đổi kiểu enum để một số loại tích phân. Đây là dấu hiệu của loại tích phân này quan trọng. Và khi chuyển đổi enum thành loại không tách rời, tuyên bố này áp dụng:

9 The value of an enumerator or an object of an enumeration type is converted to an integer by integral promotion (4.5). 

Và, rõ ràng, loại cơ bản của enum không liên quan gì đến Khuyến mại tích hợp. Kể từ khi tiêu chuẩn định nghĩa Xúc tiến Integral như thế này:

4.5 Integral promotions conv.prom 
.. An rvalue of an enumeration type (7.2) can be converted to an rvalue of the first of the following types that can represent all the values of the enumeration 
(i.e. the values in the range bmin to bmax as described in 7.2: int, unsigned int, long, or unsigned long. 

Vì vậy, cho dù một kiểu enum trở thành signed int hoặc unsigned int phụ thuộc vào việc signed int có thể chứa tất cả các giá trị của các điều tra viên xác định, không phải là loại cơ bản của enum.

Xem câu hỏi có liên quan của tôi Sign of C++ Enum Type Incorrect After Converting to Integral Type

+0

Nó quan trọng khi bạn đang biên dịch với '-Wsign-conversion'. Chúng tôi sử dụng nó để giúp bắt những sai lầm không mong muốn trong mã của chúng tôi. Nhưng *** + 1 *** để trích dẫn tiêu chuẩn, và chỉ ra rằng một enum không có kiểu ('signed' so với' unsigned') liên kết với nó. – jww

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