Perché usi typedef quando dichiari un enum in C ++?


183

Non scrivo C ++ da anni e ora sto cercando di riprenderlo. Mi sono imbattuto in questo e ho pensato di rinunciare:

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

Cos'è questo? Perché la typedefparola chiave viene utilizzata qui? Perché il nome TokenTypeappare due volte in questa dichiarazione? In che modo la semantica è diversa da questa:

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

Risposte:


156

In C, dichiarando il tuo enum il primo modo ti permette di usarlo in questo modo:

TokenType my_type;

Se usi il secondo stile, sarai costretto a dichiarare la tua variabile in questo modo:

enum TokenType my_type;

Come menzionato da altri, questo non fa differenza in C ++. La mia ipotesi è che o la persona che ha scritto questo sia un programmatore C a cuore, o stai compilando il codice C come C ++. In entrambi i casi, non influirà sul comportamento del codice.


12
La tua domanda è corretta solo per C, ma non per C ++. In C ++ enumerazioni e strutture possono essere usate direttamente come se ci fosse un typedef.
David Rodríguez - dribeas,

7
Bene, sì, ma questo risponde alla vera domanda che è stata posta che riguardava davvero "cosa significa questo?"
BobbyShaftoe,

Quindi tecnicamente questo è un refuso o un enum?
Miek,

5
Sono entrambi. Potresti anche dire: enum TokenType_ {...}; typedef enum TokenType_ TokenType;
Ryan Fox,

La risposta è completa, ma credo che il punto sia che TokenType; dopo la dichiarazione enum è ciò che sta dichiarando il nome del tipo. Quindi la risposta non è completa al 100% La dichiarazione "il primo modo" specifica ENTRAMBI un enum e un nuovo nome tipografico che è quell'enum in un blocco di sintassi. Quindi la risposta è stata utile, ma sto pensando che potrebbe essere migliorata un po '. Forse sono stato troppo duro per votare in giù. Quindi l'ho votato dopo tutto ciò. Se fossi davvero sicuro di me stesso, mi prenderei un colpo a modificare / migliorare la risposta ... ma questa è una risposta abbastanza buona
Ross Youngblood

97

È un'eredità C, in C, se lo fai:

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

dovrai usarlo facendo qualcosa del tipo:

enum TokenType foo;

Ma se lo fai:

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

Sarai in grado di dichiarare:

TokenType foo;

Ma in C ++, puoi usare solo la definizione precedente e usarla come se fosse in un typedef C.


1
Quello che dici è vero in C. Non è vero in C ++.
Jonathan Leffler,

49
Non è quello che ho detto nella mia ultima frase?
mat

2
@mat Ho votato il tuo commento sull'ultima frase, ma per essere onesti è scarsamente formulato e confuso.
AR,

20

Non è necessario farlo. In C (non C ++) è stato richiesto di utilizzare Enumame Enum per fare riferimento a un elemento di dati del tipo enumerato. Per semplificarlo, ti è stato permesso di digitarlo in un tipo di dati a nome singolo.

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

ha permesso alle funzioni che assumono un parametro dell'enum di essere definite come

void f( MyEnum x )

invece di più a lungo

void f( enum MyEnum x )

Si noti che il nome del tipo non deve essere uguale al nome dell'enum. Lo stesso accade con le strutture.

In C ++, d'altra parte, non è richiesto, poiché enum, classi e strutture sono accessibili direttamente come tipi con i loro nomi.

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

In realtà penso che questa potrebbe essere una risposta migliore di quella generalmente accettata, in quanto spiega chiaramente "perché" è diverso.
Ross Youngblood,

11

In C, è un buon stile perché puoi cambiare il tipo in qualcosa oltre a un 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 */

In C ++ è possibile definire l'enum in modo che venga compilato come C ++ o C.


Non intendi dire In C++ you can *typedef* the enum so that it will compile as C++ or C.? Hai detto: In C++ you can define the enum so that it will compile as C++ or C.nota come ho cambiato il tuo definein typedef. Beh ... suppongo che l' typedefing sia in fase di definizione.
Gabriel Staples,

6

Holdover da C.


Non so che il qualificatore 'early' è rilevante; lo scriveresti comunque in C se volessi usare il nome del tipo senza il prefisso enum.
Jonathan Leffler,

1
vero. Lo cancellerò. Non seguo le specifiche C da molto tempo. Ero troppo pigro per controllare la distinzione c / c ++ ... -1 per me.
Tim

6

Alcune persone dicono che C non ha spazi dei nomi ma ciò non è tecnicamente corretto. Ne ha tre:

  1. Tag ( enum, union, e struct)
  2. etichette
  3. (tutto il resto)

typedef enum { } XYZ;dichiara un'enumerazione anonima e la importa nello spazio dei nomi globale con il nome XYZ.

typedef enum ABC { } XYZ;dichiara un enum chiamato ABCnello spazio dei nomi dei tag, quindi lo importa nello spazio dei nomi globale come XYZ.

Alcune persone non vogliono preoccuparsi degli spazi dei nomi separati, quindi digitano tutto. Altri non scrivono mai perché vogliono lo spazio dei nomi.


Questo non è esattamente preciso. le strutture, i sindacati e gli enum sono indicati dal nome del tag (a meno che non sia anonimo, come hai detto). Esistono spazi dei nomi separati per tipi e tag. Puoi avere un tipo con lo stesso identico nome di un tag e compilare correttamente. Tuttavia, se un enum ha lo stesso tag di uno struct, si tratta di un errore di compilazione esattamente come sarebbero 2 strutture o 2 enum con lo stesso tag. Dimentichi anche che le etichette per goto sono uno spazio dei nomi separato. Un'etichetta può avere lo stesso nome di un tag o un identificatore, ma non un tipo e un identificatore può avere lo stesso nome di un tag, ma non un tipo.
Rich Jahn

3

Questo è un po 'vecchio, ma spero che apprezzerai il link che sto per scrivere come l'ho apprezzato quando l'ho trovato all'inizio di quest'anno.

Qui si tratta . Dovrei citare la spiegazione che è sempre nella mia mente quando devo cogliere alcuni brutti errori di battitura:

Nelle dichiarazioni delle variabili, i nomi introdotti sono istanze dei tipi corrispondenti. [...] Tuttavia, quando la typedefparola chiave precede la dichiarazione, i nomi introdotti sono alias dei tipi corrispondenti

Come molte persone hanno detto in precedenza, non è necessario utilizzare i typedef che dichiarano gli enum in C ++ . Ma questa è la spiegazione della sintassi del typedef! Spero che sia d'aiuto (probabilmente non OP, dato che sono passati quasi 10 anni, ma chiunque stia lottando per capire questo tipo di cose).


1

In alcune guide di codestyle C si dice che la versione typedef sia preferita per "chiarezza" e "semplicità". Non sono d'accordo, perché il typedef offusca la vera natura dell'oggetto dichiarato. In realtà, non uso typedefs perché quando dichiaro una variabile C voglio essere chiaro su cosa sia effettivamente l'oggetto. Questa scelta mi aiuta a ricordare più velocemente cosa fa effettivamente un vecchio pezzo di codice e aiuterà gli altri a mantenere il codice in futuro.


1

La risposta effettiva alla domanda "why" (che è sorprendentemente ignorata dalle risposte esistenti in cima a questa vecchia domanda) è che questa enumdichiarazione si trova probabilmente in un file header che deve essere compilato in modo incrociato come codice C e C ++ (es. incluso in entrambe le fiule di implementazione C e C ++). L'arte di scrivere tali file di intestazione si basa sulla capacità dell'autore di selezionare caratteristiche della lingua che abbiano il significato compatibile adeguato in entrambe le lingue.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.