2011-12-21 41 views
17

Xem ví dụ đơn giản bên dưới. Khi một hàm trả về một số enum được gán cho một biến khác nhau enum Tôi không nhận được bất kỳ cảnh báo nào ngay cả với gcc -Wall -pedantic. Tại sao không thể cho trình biên dịch C thực hiện kiểm tra kiểu trên enum? Hoặc là gcc cụ thể? Tôi không có quyền truy cập vào bất kỳ trình biên dịch khác ngay bây giờ để thử nó ra ..kiểm tra loại enum trong C/gcc

enum fruit { 
APPLE, 
ORANGE 
}; 

enum color { 
RED, 
GREEN 
}; 

static inline enum color get_color() { 
    return RED; 
} 

int main() { 
    enum fruit ftype; 
    ftype = get_color(); 
} 

Trả lời

26

khai này:

enum fruit { 
    apple, 
    orange 
}; 

tuyên bố ba điều: một loại gọi là enum fruit, và hai điều tra viên gọi appleorange.

enum fruit thực sự là một loại riêng biệt. Nó tương thích với một số loại số nguyên được xác định thực hiện; ví dụ: enum fruit có thể tương thích với int, với char hoặc thậm chí với unsigned long long nếu triển khai lựa chọn, miễn là loại được chọn có thể đại diện cho tất cả các giá trị.

Các điều tra viên, mặt khác, là hằng số loại int. Trong thực tế, có một mẹo phổ biến của việc sử dụng một enum khai trần tuyên bố int hằng mà không sử dụng tiền xử lý:

enum { MAX = 1000 }; 

Vâng, đó có nghĩa là hằng số apple, mặc dù nó đã được công bố như một phần của định nghĩa của enum fruit , không thực sự thuộc loại enum fruit. Lý do cho điều này là lịch sử. Và có, nó có lẽ sẽ có ý nghĩa hơn cho các điều tra viên là hằng số của loại.

Trong thực tế, sự mâu thuẫn này hiếm khi quan trọng. Trong hầu hết các ngữ cảnh, các loại rời rạc (tức là, các loại số nguyên và kiểu liệt kê) có thể hoán đổi cho nhau, và chuyển đổi ngầm thường làm đúng.

enum fruit { apple, orange }; 
enum fruit obj;  /* obj is of type enum fruit */ 
obj = orange;  /* orange is of type int; it's 
         implicitly converted to enum fruit */ 
if (obj == orange) { /* operands are converted to a common type */ 
    /* ... */ 
} 

Nhưng kết quả là, như bạn đã thấy, trình biên dịch không có khả năng cảnh báo bạn nếu bạn sử dụng một hằng số liên kết với một loại được liệt kê khi bạn có nghĩa là sử dụng một tên khác.

Một cách để có được mạnh mẽ kiểu kiểm tra là để bọc dữ liệu của bạn trong một cấu trúc:

enum fruit { /* ... */ }; 
enum color { /* ... */ }; 
struct fruit { enum fruit f; }; 
struct color { enum color c; }; 

struct fruitstruct color nhiều loại khác nhau và không phù hợp với không chuyển đổi ngầm (hoặc rõ ràng) giữa chúng. Nhược điểm là bạn phải tham khảo rõ ràng thành viên .f hoặc .c. (Hầu hết các lập trình viên C chỉ dựa vào khả năng của họ để có được những điều đúng ngay từ đầu - với kết quả hỗn hợp.)

(typedef không cung cấp cho bạn kiểm tra kiểu mạnh mẽ; bất kể tên, nó tạo bí danh cho hiện tại loại, không phải là một loại mới).

(Các quy tắc trong C++ là một chút khác nhau.)

2

Đó là bởi vì enum s trong C chỉ đơn giản là một nhóm các hằng số nguyên duy nhất, giúp bạn tiết kiệm từ việc phải #define cả một bó của các hằng số. Nó không giống như C++ trong đó các bạn đang tạo một loại cụ thể là enum. Đó chỉ là cách C.

Cũng cần lưu ý rằng kích thước thực tế được sử dụng để thể hiện các giá trị enum tùy thuộc vào trình biên dịch.

1

Một enum trong C về cơ bản được xử lý như một số nguyên. Nó chỉ là một cách tốt hơn để sử dụng hằng số.

// this would work as well 
    ftype = 1; 

Bạn cũng có thể chỉ định các giá trị:

enum color { 
    RED=0,GREEN,BLUE 
    } mycolor; 

    mycolor = 1; // GREEN 
3

gcc quyết định không để cảnh báo (cũng như clang) nhưng icc (biên dịch Intel) sẽ cảnh báo trong tình huống này. Nếu bạn muốn kiểm tra loại bổ sung cho các loại enum, bạn có thể chuyển mã của mình tới một số phần mềm kiểm tra mã tĩnh như Lint có thể cảnh báo trong các trường hợp như vậy.

gcc quyết định đó không phải là hữu ích để cảnh báo cho các chuyển đổi ngầm giữa enum loại nhưng cũng lưu ý rằng C không yêu cầu thực hiện để đưa ra một chẩn đoán trong trường hợp chuyển nhượng giữa hai enum loại khác nhau. Điều này tương tự như việc chuyển nhượng giữa bất kỳ loại số học nào: không bắt buộc phải có chẩn đoán C. Ví dụ: gcc cũng sẽ không cảnh báo nếu bạn chỉ định long long cho số char hoặc short đến long.

5

Có lẽ hầu hết chúng ta hiểu nguyên nhân cơ bản ("spec nói rằng nó phải hoạt động"), nhưng chúng tôi cũng đồng ý rằng đây là nguyên nhân gây ra nhiều lỗi lập trình trong vùng "C" và giải pháp cấu trúc gói là Tổng. Bỏ qua các trình kiểm tra bổ trợ như lint, dưới đây là những gì chúng tôi có:

gcc (4.9): No warning available. 
microsoft cl (18.0): No warning available. 
clang (3.5): YES -Wenum-conversion 
+0

Tất cả mưa đá của Apple/LLVM. Tôi tin rằng 3 trình biên dịch bao gồm khá nhiều tất cả các hệ điều hành chính (iOS, Android, Microsoft, OSX), nhưng bất kỳ cập nhật thú vị khác được đánh giá cao. Tôi tin rằng một bài viết trước đề cập đến icc, nhưng tôi không có quyền truy cập vào đó. –