2015-05-23 15 views
6

Nếu tôi có một kiểu enum, như:Tràn của một loại enum trong C?

enum week{ sunday=0, monday, tuesday, wednesday, thursday, friday, saturday};

và tôi có:

enum week day; 
day = saturday; 
day++; 

gì sẽ là giá trị trong ngày?

+5

Không xác định. –

+1

Điều này có vẻ giống như loại điều bạn có thể giải quyết bằng cách kiểm tra trình biên dịch của bạn trong hai giây 'printf ("% d \ n ", ++ (ngày = thứ bảy));' .Tất nhiên, nếu bạn phải hỏi, bạn có lẽ không nên đặt nó trong một chương trình, dù sao, vì nó được đảm bảo trông giống như một lỗi mỗi lần sau khi bạn đọc nó. –

+2

Thực tế là nó biên dịch và thực hiện không đảm bảo rằng hành vi của nó không phải là không xác định, mặc dù. Tiền của tôi nói rằng mã bạn đăng sẽ * luôn * in 7, nhưng tôi muốn thấy một dòng từ một đặc điểm kỹ thuật. – fzzfzzfzz

Trả lời

2

Loại được liệt kê về bản chất là một giá trị tích phân được đặt tên. Kiểu liệt kê đó được liên kết với một kiểu tích phân cơ bản có thể đại diện cho tất cả các giá trị được đặt tên. Kiểu tích phân cơ bản đó là bắt buộc để có thể biểu diễn tất cả các giá trị được đặt tên duy nhất, nhưng loại thực tế của nó được thực hiện được xác định.

Trong trường hợp này, giá trị số của saturday sẽ là 6. Gia tăng nó sẽ cho giá trị số là 7. Trong thực tế, không có khả năng làm tràn loại tích phân cơ bản (int, char, unsigned char hoặc bất kỳ trình biên dịch nào chọn), do đó, in giá trị sử dụng định dạng %d sẽ in 7.

Tuy nhiên, không có giá trị được liệt kê (có tên) thuộc loại enum week với giá trị là 7.

Nếu tăng giá trị được liệt kê sẽ làm tràn loại tích phân cơ bản (không phải trường hợp ở đây) thì kết quả là không xác định. Điều này là do loại tích phân cơ bản có thể được ký hoặc không ký, và tràn một loại tích phân đã ký cho hành vi không xác định.

Về mặt lý thuyết, nó có thể là một trình biên dịch có thể sử dụng một loại cơ bản cho enum week mà chỉ có thể đại diện cho các giá trị 0-6 - trong trường hợp incrementing mà saturday cho hành vi không xác định. Trong thực tế, AFAIK, vẫn chưa có trình biên dịch C nào không chọn loại cơ bản là một trong các loại tích phân chuẩn (char, int, unsigned char, unsigned, v.v ...). Tất cả các loại đó có thể đại diện cho giá trị số là 7.

+0

Chuẩn có cho phép một chế độ gỡ lỗi biên dịch thời gian chạy-kiểm tra các giá trị được lưu trữ trong enum để đảm bảo chúng nằm trong phạm vi không? –

+0

Tiêu chuẩn không ngăn và cũng không yêu cầu chế độ gỡ lỗi như vậy. – Peter

+1

@MarkRansom: Tiêu chuẩn ngăn chặn chế độ gỡ lỗi như vậy hoặc ít nhất chỉ định rằng nó không phù hợp. Giá trị của 'ngày' sau' ngày ++ 'là' 7'.Việc triển khai tuân thủ là miễn phí để đưa ra cảnh báo biên dịch (về điều đó hoặc bất kỳ điều gì khác), nhưng nó không được phép làm bất cứ điều gì trong thời gian chạy khác ngoài việc lưu trữ giá trị '7' trong' ngày'. Tất nhiên các trình biên dịch được tự do cung cấp một chế độ không phù hợp với tiêu chuẩn vì lợi ích nếu áp đặt các kiểm tra bổ sung. –

1

Tôi chỉ có thể tìm thấy bản nháp của đặc điểm kỹ thuật C89 và tôi không phải là chuyên gia về C, vì vậy tôi có thể hiểu nhầm. Nhưng phần của nó 3.5.2.2 nói rằng

Các định danh trong danh sách điều tra viên được khai báo là hằng số có kiểu int và có thể xuất hiện bất cứ nơi nào như vậy được phép. [...] Mỗi loại được liệt kê phải tương thích với một loại số nguyên.

Tôi nghĩ đó có nghĩa là day++ sẽ luôn mang lại 7 đây (một nhiều hơn giá trị đại diện bởi saturday).

1

Given:

enum week { 
    sunday=0, monday, tuesday, wednesday, thursday, friday, saturday 
}; 
enum week day = saturday; 
day ++; 

giá trị của day7.

Trích dẫn tiêu chuẩn ISO C 2011, 6.7.2.2 đoạn 1:

Mỗi kiểu liệt kê phải tương thích với char, một loại nguyên ký , hoặc một loại unsigned integer. Lựa chọn loại là được xác định thực hiện, nhưng phải có khả năng đại diện cho các giá trị của tất cả các thành viên của điều tra.

_Bool là loại số nguyên không dấu, nhưng không đáp ứng các yêu cầu cho loại liệt kê cụ thể này.

Kể từ khi giá trị của CHAR_BIT được yêu cầu phải có ít nhất 8, và các loại char, unsigned char, và signed char được yêu cầu không có bit đệm, phạm vi của mỗi loại nhân vật phải bao gồm ít nhất 0 qua 127. Các loại số nguyên rộng hơn (short, int, v.v.) có phạm vi rộng ít nhất là signed char hoặc unsigned char. Do đó loại thực hiện được xác định tương thích với enum week phải có giới hạn dưới không lớn hơn 0 và giới hạn trên không ít hơn 127.

(CẢNH BÁO: Ngôn ngữ-bào chữa sau.) Có thể có một lỗ hổng cho phép loại nguyên mở rộng với một phạm vi rộng hơn _Bool nhưng một phạm vi hẹp hơn char. Ví dụ: Tôi nghĩ rằng loại số nguyên mở rộng có kích thước 8 bit nhưng chỉ có 3 bit giá trị hợp pháp. Nhưng vì các kiểu số nguyên được yêu cầu sử dụng một biểu diễn nhị phân, một kiểu unsigned với 3 bit giá trị sẽ có thể biểu diễn các giá trị từ 0 đến 7, và một loại unsigned với 2 bit giá trị sẽ không thể đại diện cho giá trị của saturday. Vì enum week có thể giữ giá trị 6, nó cũng phải có thể giữ giá trị 7. Trong việc triển khai không bình thường, có thể không thể đại diện cho giá trị 8, nhưng bạn không thể gặp phải việc triển khai như vậy. Về cơ bản, với yêu cầu các kiểu số nguyên sử dụng một biểu diễn nhị phân thuần túy, bất kỳ kiểu nào có thể đại diện cho 6 cũng có thể đại diện cho 7, mặc dù nó không tự động theo sau nó cũng có thể đại diện cho 8.