Mengapa Anda menggunakan typedef ketika mendeklarasikan enum di C ++?

183

Saya belum pernah menulis C ++ selama bertahun-tahun dan sekarang saya mencoba untuk kembali ke dalamnya. Saya kemudian berlari melintasi ini dan berpikir untuk menyerah:

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

Apa ini? Kenapa itutypedef kata kunci digunakan di sini? Mengapa nama itu TokenTypemuncul dua kali dalam deklarasi ini? Apa perbedaan antara semantik dengan ini:

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

Jawaban:

156

Di C, mendeklarasikan enum Anda dengan cara pertama memungkinkan Anda untuk menggunakannya seperti:

TokenType my_type;

Jika Anda menggunakan gaya kedua, Anda akan dipaksa untuk mendeklarasikan variabel Anda seperti ini:

enum TokenType my_type;

Seperti yang disebutkan oleh orang lain, ini tidak membuat perbedaan dalam C ++. Dugaan saya adalah orang yang menulis ini adalah pemrogram C, atau Anda mengkompilasi kode C sebagai C ++. Either way, itu tidak akan mempengaruhi perilaku kode Anda.

Ryan Fox
sumber
12
Pertanyaan Anda hanya benar untuk C, tetapi tidak untuk C ++. Dalam C ++ enum dan struct dapat digunakan secara langsung seolah-olah ada typedef.
David Rodríguez - dribeas
7
Ya, tapi ini menjawab pertanyaan sebenarnya yang diajukan yang sebenarnya tentang "apa artinya ini?"
BobbyShaftoe
Jadi, apakah ini secara teknis typedef atau enum?
Miek
5
Keduanya. Anda juga bisa mengatakan: enum TokenType_ {...}; typedef enum TokenType_ TokenType;
Ryan Fox
Jawabannya lengkap, tapi saya percaya intinya adalah bahwa TokenType; setelah deklarasi enum adalah apa yang mendeklarasikan nama tipe. Jadi jawabannya tidak 100% lengkap. Mendeklarasikan 'cara pertama' menentukan KEDUA enum dan nama ketik baru yaitu enum dalam satu gumpalan sintaks. Jadi jawabannya sangat membantu, tapi saya pikir bisa ditingkatkan sedikit. Mungkin saya terlalu keras untuk memilih. Jadi saya membatalkannya setelah semua itu. Jika saya benar-benar yakin pada diri saya sendiri, saya akan mengambil risiko dalam mengedit / meningkatkan jawaban ... tapi ini adalah jawaban yang cukup bagus
Ross Youngblood
97

Ini adalah warisan C, di C, jika Anda melakukannya:

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

Anda harus menggunakannya untuk melakukan sesuatu seperti:

enum TokenType foo;

Tetapi jika Anda melakukan ini:

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

Anda akan dapat mendeklarasikan:

TokenType foo;

Tetapi dalam C ++, Anda hanya bisa menggunakan definisi sebelumnya dan menggunakannya seolah-olah itu dalam C typedef.

tikar
sumber
1
Apa yang Anda katakan itu benar dalam C. Itu tidak benar dalam C ++.
Jonathan Leffler
49
Bukankah itu yang saya katakan dalam kalimat terakhir saya?
mat
2
@ Ah, saya membenarkan komentar Anda tentang kalimat terakhir, tetapi untuk bersikap adil itu adalah kata-kata yang buruk dan membingungkan.
AR
20

Anda tidak perlu melakukannya. Dalam C (bukan C ++) Anda diminta untuk menggunakan enum Enumname untuk merujuk ke elemen data dari tipe yang disebutkan. Untuk mempermudah, Anda diizinkan untuk typedef ke tipe data nama tunggal.

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

fungsi yang diizinkan mengambil parameter enum untuk didefinisikan sebagai

void f( MyEnum x )

bukannya lebih lama

void f( enum MyEnum x )

Perhatikan bahwa nama nama ketik tidak harus sama dengan nama enum. Hal yang sama terjadi dengan struct.

Di C ++, di sisi lain, itu tidak diperlukan, karena enum, kelas dan struct dapat diakses secara langsung sebagai tipe dengan nama mereka.

// C++
enum MyEnum {
   // ...
};
void f( MyEnum x ); // Correct C++, Error in C
David Rodríguez - dribeas
sumber
Sebenarnya saya pikir ini mungkin jawaban yang lebih baik daripada yang diterima secara umum, karena ini menjelaskan dengan jelas "mengapa" itu berbeda.
Ross Youngblood
11

Di C, itu adalah gaya yang baik karena Anda dapat mengubah jenisnya menjadi sesuatu selain 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 */

Di C ++ Anda bisa mendefinisikan enum sehingga akan dikompilasi sebagai C ++ atau C.

BeWarned
sumber
Apakah Anda tidak bermaksud mengatakannya In C++ you can *typedef* the enum so that it will compile as C++ or C.? Anda mengatakan: In C++ you can define the enum so that it will compile as C++ or C.Perhatikan bagaimana saya mengubah Anda defineuntuk typedef. Yah ... Saya kira typedefing adalah mendefinisikan.
Gabriel Staples
6

Penarikan dari C.

Tim
sumber
Tidak tahu bahwa kualifikasi 'awal' itu relevan; Anda masih akan menulis itu dalam C jika Anda ingin menggunakan nama jenis tanpa awalan enum.
Jonathan Leffler
1
benar. Saya akan menghapusnya. Saya belum mengikuti spesifikasi C untuk waktu yang lama. Saya terlalu malas untuk memeriksa perbedaan c / c ++ ... -1 untuk saya.
Tim
6

Beberapa orang mengatakan C tidak memiliki ruang nama tetapi itu secara teknis tidak benar. Ada tiga:

  1. Tags ( enum, union, danstruct )
  2. Label
  3. (yang lainnya)

typedef enum { } XYZ;mendeklarasikan enumerasi anonim dan mengimpornya ke namespace global dengan nama tersebut XYZ.

typedef enum ABC { } XYZ; mendeklarasikan enum bernama ABC dalam tag namespace, lalu mengimpornya ke namespace global sebagai XYZ.

Beberapa orang tidak ingin repot dengan ruang nama yang terpisah sehingga mereka mengetik semuanya. Lainnya tidak pernah mengetik karena mereka ingin penamaan namespace.

russbishop
sumber
Ini tidak sepenuhnya akurat. struct, serikat pekerja, dan enum dirujuk oleh nama tag (kecuali anonim, seperti yang Anda sebutkan). Ada ruang nama terpisah untuk jenis dan tag. Anda dapat memiliki jenis dengan nama yang sama persis dengan tag dan kompilasi denda. Namun, jika enum memiliki tag yang sama dengan struct, ini adalah kesalahan kompilasi persis seperti 2 struct atau 2 enum dengan tag yang sama. Anda juga lupa bahwa label untuk goto adalah ruang nama yang terpisah. Label dapat berupa nama yang sama dengan tag, atau pengidentifikasi, tetapi bukan tipe, dan pengidentifikasi dapat memiliki nama yang sama dengan tag, tetapi bukan tipe.
Rich Jahn
3

Ini agak tua, tapi bagaimanapun, saya harap Anda akan menghargai tautan yang akan saya ketik saat saya menghargainya ketika saya menemukannya di awal tahun ini.

Ini dia . Saya harus mengutip penjelasan yang selalu ada di pikiran saya ketika saya harus memahami beberapa typedef jahat:

Dalam deklarasi variabel, nama yang diperkenalkan adalah contoh dari tipe yang sesuai. [...] Namun, ketika typedefkata kunci mendahului deklarasi, nama yang diperkenalkan adalah alias dari jenis yang sesuai

Seperti yang banyak orang katakan sebelumnya, tidak perlu menggunakan typedef untuk mendeklarasikan enum di C ++ . Tapi itulah penjelasan dari sintaks typedef! Saya harap ini membantu (Mungkin bukan OP, karena sudah hampir 10 tahun, tetapi siapa pun yang berjuang untuk memahami hal-hal semacam ini).

Francisco Orlandini
sumber
1

Dalam beberapa panduan gaya kode C versi typedef dikatakan lebih disukai untuk "kejelasan" dan "kesederhanaan". Saya tidak setuju, karena typedef mengaburkan sifat asli dari objek yang dinyatakan. Bahkan, saya tidak menggunakan typedef karena ketika mendeklarasikan variabel C saya ingin menjadi jelas tentang apa objek sebenarnya. Pilihan ini membantu saya untuk mengingat lebih cepat apa yang sebenarnya dilakukan oleh sepotong kode lama, dan akan membantu orang lain ketika menjaga kode di masa depan.

AdRiX
sumber
1

Jawaban aktual untuk pertanyaan "mengapa" (yang secara mengejutkan diabaikan oleh jawaban yang ada di atas pertanyaan lama ini) adalah bahwa enumpernyataan ini mungkin terletak di file header yang dimaksudkan untuk dapat dikompilasi silang karena kode C dan C ++ (yaitu dimasukkan ke dalam Cules implementasi C dan C ++). Seni menulis file header seperti itu bergantung pada kemampuan penulis untuk memilih fitur bahasa yang memiliki arti kompatibel yang tepat dalam kedua bahasa.

Semut
sumber