Tại sao bạn sử dụng typedef khi khai báo enum trong C ++?


183

Tôi đã không viết bất kỳ C ++ nào trong nhiều năm và bây giờ tôi đang cố gắng quay lại với nó. Sau đó tôi chạy qua đây và nghĩ về việc từ bỏ:

typedef enum TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
} TokenType;

Cái này là cái gì? Tại sao typedeftừ khóa được sử dụng ở đây? Tại sao tên TokenTypexuất hiện hai lần trong tuyên bố này? Các ngữ nghĩa khác nhau như thế nào:

enum TokenType
{
    blah1 = 0x00000000,
    blah2=0x01000000,
    blah3=0x02000000
};

Câu trả lời:


156

Trong C, khai báo enum của bạn theo cách đầu tiên cho phép bạn sử dụng nó như vậy:

TokenType my_type;

Nếu bạn sử dụng kiểu thứ hai, bạn sẽ buộc phải khai báo biến của mình như thế này:

enum TokenType my_type;

Như đã đề cập bởi những người khác, điều này không tạo ra sự khác biệt trong C ++. Tôi đoán là một trong những người đã viết đây là một lập trình viên C, hoặc bạn đang biên dịch mã C thành C ++. Dù bằng cách nào, nó sẽ không ảnh hưởng đến hành vi của mã của bạn.


12
Câu hỏi của bạn chỉ đúng với C, nhưng không phải C ++. Trong C ++ enum và structs có thể được sử dụng trực tiếp như thể có một typedef.
David Rodríguez - dribeas

7
Vâng, có nhưng điều này không trả lời câu hỏi thực sự đã được hỏi mà thực sự là về "điều này thậm chí có nghĩa là gì?"
BobbyShaftoe

Vì vậy, đây là kỹ thuật typedef hoặc enum?
Miek

5
Đó là cả hai. Bạn cũng có thể nói: enum TokenType_ {...}; typedef enum TokenType_ TokenType;
Ryan Fox

Câu trả lời đã hoàn tất, nhưng tôi tin rằng vấn đề là TokenType; sau khai báo enum là những gì đang khai báo tên loại. Vì vậy, câu trả lời không hoàn thành 100% Khai báo 'cách thứ nhất' chỉ định CẢ HAI một enum và một kiểu chữ mới đó là enum trong một đốm cú pháp. Vì vậy, câu trả lời là hữu ích, nhưng tôi nghĩ có thể được cải thiện một chút. Có lẽ tôi đã quá khắc nghiệt để bỏ phiếu. Vì vậy, tôi đã nâng cao nó sau tất cả điều đó. Nếu tôi thực sự chắc chắn về bản thân mình, tôi sẽ mất một chút thời gian để chỉnh sửa / cải thiện câu trả lời ... nhưng đây là một câu trả lời khá hay
Ross Youngblood

97

Đó là di sản C, ở C, nếu bạn làm:

enum TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
};

bạn sẽ phải sử dụng nó để làm một cái gì đó như:

enum TokenType foo;

Nhưng nếu bạn làm điều này:

typedef enum e_TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
} TokenType;

Bạn sẽ có thể tuyên bố:

TokenType foo;

Nhưng trong C ++, bạn chỉ có thể sử dụng định nghĩa trước đây và sử dụng nó như thể nó nằm trong một typedef C.


1
Những gì bạn nói là đúng trong C. Nó không đúng trong C ++.
Jonathan Leffler

49
Không phải là những gì tôi nói trong câu cuối cùng của tôi?
mat

2
@mat Tôi nêu lên nhận xét của bạn về câu cuối cùng, nhưng công bằng mà nói thì nó kém từ và khó hiểu.
AR

20

Bạn không cần phải làm điều đó. Trong C (không phải C ++), bạn được yêu cầu sử dụng enum Enumname để chỉ một yếu tố dữ liệu thuộc kiểu liệt kê. Để đơn giản hóa nó, bạn được phép typedef nó vào một loại tên dữ liệu duy nhất.

typedef enum MyEnum { 
  //...
} MyEnum;

các hàm được phép lấy tham số của enum được định nghĩa là

void f( MyEnum x )

thay vì dài hơn

void f( enum MyEnum x )

Lưu ý rằng tên của kiểu chữ không cần phải bằng tên của enum. Điều tương tự cũng xảy ra với các cấu trúc.

Mặt khác, trong C ++, không bắt buộc, vì enums, class và structs có thể được truy cập trực tiếp dưới dạng các loại theo tên của chúng.

// C++
enum MyEnum {
   // ...
};
void f( MyEnum x ); // Correct C++, Error in C

Trên thực tế tôi nghĩ rằng đây có thể là một câu trả lời tốt hơn so với câu trả lời thường được chấp nhận, vì nó giải thích rõ ràng "tại sao" nó khác nhau.
Ross Youngblood

11

Trong C, đó là phong cách tốt vì bạn có thể thay đổi loại thành thứ gì đó bên cạnh enum.

typedef enum e_TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
} TokenType;

foo(enum e_TokenType token);  /* this can only be passed as an enum */

foo(TokenType token); /* TokenType can be defined to something else later
                         without changing this declaration */

Trong C ++, bạn có thể định nghĩa enum để nó sẽ biên dịch thành C ++ hoặc C.


Bạn không có ý muốn nói In C++ you can *typedef* the enum so that it will compile as C++ or C.sao? Bạn nói: In C++ you can define the enum so that it will compile as C++ or C.Lưu ý cách tôi thay đổi definethành typedef. Chà ... tôi cho rằng typedefing đang xác định.
Gabriel Staples

6

Tiếp quản từ C.


Dunno rằng vòng loại 'sớm' có liên quan; bạn vẫn sẽ viết nó trong C nếu bạn muốn sử dụng tên loại mà không có tiền tố enum.
Jonathan Leffler

1
thật. Tôi sẽ xóa nó. Tôi đã không theo dõi C spec trong một thời gian dài. Tôi đã quá lười biếng để kiểm tra sự khác biệt của c / c ++ ... -1 đối với tôi.
Tim

6

Một số người nói C không có không gian tên nhưng điều đó không đúng về mặt kỹ thuật. Nó có ba:

  1. Tags ( enum, unionstruct)
  2. Nhãn
  3. (mọi thứ khác)

typedef enum { } XYZ;tuyên bố một bảng liệt kê ẩn danh và nhập nó vào không gian tên toàn cầu với tên đó XYZ.

typedef enum ABC { } XYZ;khai báo một enum có tên ABCtrong không gian tên thẻ, sau đó nhập nó vào không gian tên toàn cục như XYZ.

Một số người không muốn bận tâm đến các không gian tên riêng biệt nên họ đã gõ mọi thứ. Những người khác không bao giờ đánh máy vì họ muốn không gian tên.


Điều này không chính xác chính xác. cấu trúc, công đoàn và enum được tham chiếu theo tên thẻ (trừ khi ẩn danh, như bạn đã đề cập). Có các không gian tên riêng cho các loại và thẻ. Bạn có thể có một loại có cùng tên chính xác như một thẻ và biên dịch tốt. Tuy nhiên, nếu một enum có cùng một thẻ với cấu trúc, thì đây là lỗi biên dịch chính xác như 2 structs hoặc 2 enum với cùng một thẻ. Bạn cũng quên rằng các nhãn cho goto là một không gian tên riêng biệt. Một nhãn có thể cùng tên với một thẻ hoặc một mã định danh, nhưng không phải là một loại và một mã định danh có thể có cùng tên với một thẻ, nhưng không phải là một loại.
Rich Jahn

3

Đây là một loại cũ, nhưng dù sao, tôi hy vọng bạn sẽ đánh giá cao liên kết mà tôi sắp gõ vì tôi đánh giá cao nó khi tôi bắt gặp nó vào đầu năm nay.

Ở đây nó là . Tôi nên trích dẫn lời giải thích luôn ở trong tâm trí tôi khi tôi phải nắm bắt một số typedefs khó chịu:

Trong khai báo biến, các tên được giới thiệu là thể hiện của các loại tương ứng. [...] Tuy nhiên, khi typedeftừ khóa đi trước khai báo, các tên được giới thiệu là bí danh của các loại tương ứng

Như nhiều người đã nói trước đây, không cần phải sử dụng typedefs khai báo enum trong C ++ . Nhưng đó là lời giải thích về cú pháp của typedef! Tôi hy vọng nó có ích (Có lẽ không phải OP, vì đã gần 10 năm, nhưng bất kỳ ai đang đấu tranh để hiểu những thứ này).


1

Trong một số hướng dẫn về mã hóa C, phiên bản typedef được cho là ưu tiên cho "sự rõ ràng" và "đơn giản". Tôi không đồng ý, vì typedef làm xáo trộn bản chất thực sự của đối tượng khai báo. Trên thực tế, tôi không sử dụng typedefs vì khi khai báo biến C tôi muốn rõ ràng về đối tượng thực sự là gì. Lựa chọn này giúp bản thân tôi nhớ nhanh hơn những gì một đoạn mã cũ thực sự làm và sẽ giúp người khác khi duy trì mã trong tương lai.


1

Câu trả lời thực sự cho câu hỏi "tại sao" (bị bỏ qua một cách đáng ngạc nhiên bởi các câu trả lời hiện có trên câu hỏi cũ này) là enumtuyên bố này có thể nằm trong một tệp tiêu đề có thể được biên dịch chéo cả mã C và C ++ (nghĩa là được bao gồm trong cả hai tập tin triển khai C và C ++). Nghệ thuật viết các tệp tiêu đề như vậy phụ thuộc vào khả năng của tác giả trong việc chọn các tính năng ngôn ngữ có ý nghĩa tương thích phù hợp trong cả hai ngôn ngữ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.