Come definire un tipo enumerato (enum) in C?

Non sono sicuro di quale sia la syntax corretta per l’utilizzo di enumerazioni C. Ho il codice seguente:

enum {RANDOM, IMMEDIATE, SEARCH} strategy; strategy = IMMEDIATE; 

Ma questo non si compila, con il seguente errore:

 error: conflicting types for 'strategy' error: previous declaration of 'strategy' was here 

Che cosa sto facendo di sbagliato?

Dichiarare una variabile enum è fatta in questo modo:

 enum strategy {RANDOM, IMMEDIATE, SEARCH}; enum strategy my_strategy = IMMEDIATE; 

Tuttavia, puoi usare un typedef per abbreviare le dichiarazioni delle variabili, in questo modo:

 typedef enum {RANDOM, IMMEDIATE, SEARCH} strategy; strategy my_strategy = IMMEDIATE; 

Avere una convenzione di denominazione per distinguere tra tipi e variabili è una buona idea:

 typedef enum {RANDOM, IMMEDIATE, SEARCH} strategy_type; strategy_type my_strategy = IMMEDIATE; 

Vale la pena sottolineare che non è necessario un typedef . Puoi farlo come il seguente

 enum strategy { RANDOM, IMMEDIATE, SEARCH }; enum strategy my_strategy = IMMEDIATE; 

È una domanda di stile, che tu preferisca typedef . Senza di esso, se si desidera fare riferimento al tipo di enumerazione, è necessario utilizzare la enum strategy . Con esso, puoi solo dire strategy .

Entrambi i modi hanno i loro pro e contro. L’uno è più verboso, ma mantiene gli identificatori di tipo nello spazio dei nomi dei tag in cui non entrano in conflitto con gli identificatori ordinari (si pensi alle struct stat e alle stat : queste non sono in conflitto) e dove si vede immediatamente che è un genere. L’altro è più breve, ma porta gli identificatori di tipo nello spazio dei nomi ordinario.

Stai tentando di dichiarare la strategy due volte, ed è per questo che stai ricevendo l’errore sopra riportato. I seguenti lavori senza lamentele (compilati con gcc -ansi -pendantic -Wall ):

 #include  enum { RANDOM, IMMEDIATE, SEARCH } strategy = IMMEDIATE; int main(int argc, char** argv){ printf("strategy: %d\n", strategy); return 0; } 

Se invece di quanto sopra, la seconda riga è stata modificata in:

 ... enum { RANDOM, IMMEDIATE, SEARCH } strategy; strategy = IMMEDIATE; ... 

Dalle avvertenze, potresti facilmente vedere il tuo errore:

 enums.c:5:1: warning: data definition has no type or storage class [enabled by default] enums.c:5:1: warning: type defaults to 'int' in declaration of 'strategy' [-Wimplicit-int] enums.c:5:1: error: conflicting types for 'strategy' enums.c:4:36: note: previous declaration of 'strategy' was here 

Quindi il compilatore ha preso la strategy = IMMEDIATE per una dichiarazione di una variabile chiamata strategy con tipo di default int , ma c’era già una dichiarazione precedente di una variabile con questo nome.

Tuttavia, se hai inserito il compito nella funzione main() , sarebbe un codice valido:

 #include  enum { RANDOM, IMMEDIATE, SEARCH } strategy = IMMEDIATE; int main(int argc, char** argv){ strategy=SEARCH; printf("strategy: %d\n", strategy); return 0; } 

Quando dici

 enum {RANDOM, IMMEDIATE, SEARCH} strategy; 

crei una singola variabile di istanza, chiamata ‘strategia’ di un enum senza nome. Questa non è una cosa molto utile da fare – hai bisogno di un typedef:

 typedef enum {RANDOM, IMMEDIATE, SEARCH} StrategyType; StrategyType strategy = IMMEDIATE; 

Come scritto, non c’è niente di sbagliato nel tuo codice. Sei sicuro di non aver fatto qualcosa del genere

 int strategy; ... enum {RANDOM, IMMEDIATE, SEARCH} strategy; 

A quali linee puntano i messaggi di errore? Quando dice “la precedente dichiarazione di ‘strategia’ era qui”, cosa c’è “qui” e cosa mostra?

@ThoAppelsin nel suo commento alla domanda pubblicata ha ragione. Lo snippet di codice pubblicato nella domanda è valido e senza errori. L’errore che hai deve essere dovuto ad altre cattive syntax in qualsiasi altra parte del tuo file sorgente c. enum{a,b,c}; definisce tre costanti simboliche ( a , b e c ) che sono rispettivamente interi con i valori 0 , 1 e 2 , ma quando usiamo enum è perché di solito non ci interessa il valore intero specifico, ci interessa più del significato di il nome della costante simbolica. Questo significa che puoi avere questo:

 #include  enum {a,b,c}; int main(){ printf("%d\n",b); return 0; } 

e questo uscirà 1 .

Anche questo sarà valido:

 #include  enum {a,b,c}; int bb=b; int main(){ printf("%d\n",bb); return 0; } 

e uscirà come prima.

Se lo fai:

 enum {a,b,c}; enum {a,b,c}; 

avrai un errore, ma se lo fai:

 enum alfa{a,b,c}; enum alfa; 

non avrai alcun errore.

Puoi farlo:

 enum {a,b,c}; int aa=a; 

e aa sarà una variabile intera con valore 0 . ma puoi anche farlo:

 enum {a,b,c} aa= a; 

e avrà lo stesso effetto (cioè, essendo un valore int con valore 0 ).

puoi anche fare questo:

 enum {a,b,c} aa= a; aa= 7; 

e aa sarà int con valore 7 .

perché non è ansible ripetere la definizione di una costante simbolica con l’uso di enum , come ho detto in precedenza, è necessario utilizzare i tag se si desidera dichiarare vars int con l’uso di enum :

 enum tag1 {a,b,c}; enum tag1 var1= a; enum tag1 var2= b; 

l’uso di typedef consente di enum tag1 ogni volta la scrittura di enum tag1 per definire la variabile. Con typedef puoi semplicemente digitare Tag1 :

 typedef enum {a,b,c} Tag1; Tag1 var1= a; Tag1 var2= b; 

Puoi anche avere:

 typedef enum tag1{a,b,c}Tag1; Tag1 var1= a; enum tag1 var2= b; 

L’ultima cosa da dire è che, dal momento che stiamo parlando di costanti simboliche definite, è meglio usare lettere maiuscole quando si usa enum , cioè per esempio:

 enum {A,B,C}; 

invece di

 enum {a,b,c}; 

Vale la pena ricordare che in C ++ è ansible utilizzare “enum” per definire un nuovo tipo senza bisogno di un’istruzione typedef.

 enum Strategy {RANDOM, IMMEDIATE, SEARCH}; ... Strategy myStrategy = IMMEDIATE; 

Trovo questo approccio molto più amichevole.

[modifica – stato C ++ chiarito – ho avuto questo in origine, quindi rimosso!]

Sembra che ci sia una confusione riguardo alla dichiarazione.

Quando la strategy viene prima di {RANDOM, IMMEDIATE, SEARCH} come di seguito,

 enum strategy {RANDOM, IMMEDIATE, SEARCH}; 

stai creando un nuovo tipo chiamato enum strategy . Tuttavia, quando si dichiara la variabile, è necessario utilizzare la stessa enum strategy . Non puoi semplicemente usare la strategy . Quindi quanto segue non è valido.

 enum strategy {RANDOM, IMMEDIATE, SEARCH}; strategy a; 

Mentre, il seguente è valido

 enum strategy {RANDOM, IMMEDIATE, SEARCH}; enum strategy queen = RANDOM; enum strategy king = SEARCH; enum strategy pawn[100]; 

Quando la strategy viene dopo {RANDOM, IMMEDIATE, SEARCH} , stai creando un enum anonimo e quindi dichiarando che la strategy è una variabile di quel tipo.

Quindi ora puoi fare qualcosa del genere

 enum {RANDOM, IMMEDIATE, SEARCH} strategy; strategy = RANDOM; 

Tuttavia, non puoi dichiarare alcuna altra variabile di tipo enum {RANDOM, IMMEDIATE, SEARCH} perché non l’hai mai chiamata. Quindi quanto segue non è valido

 enum {RANDOM, IMMEDIATE, SEARCH} strategy; enum strategy a = RANDOM; 

Puoi combinare entrambe le definizioni

 enum strategy {RANDOM, IMMEDIATE, SEARCH} a, b; a = RANDOM; b = SEARCH; enum strategy c = IMMEDIATE; 

Typedef come indicato in precedenza viene utilizzato per creare una dichiarazione variabile più breve.

 typedef enum {RANDOM, IMMEDIATE, SEARCH} strategy; 

Ora hai detto al compilatore che enum {RANDOM, IMMEDIATE, SEARCH} è sinonimo di strategy . Quindi ora puoi usare liberamente la strategy come tipo variabile. Non è più necessario digitare la enum strategy . Quanto segue è valido ora

 strategy x = RANDOM; 

Puoi anche combinare Typedef con il nome enum per ottenere

 typedef enum strategyName {RANDOM, IMMEDIATE, SEARCH} strategy; 

Non c’è molto vantaggio nell’usare questo metodo a parte il fatto che ora puoi usare la strategy e enum strategyName intercambiabile.

 typedef enum strategyName {RANDOM, IMMEDIATE, SEARCH} strategy; enum strategyName a = RANDOM; strategy b = SEARCH; 

Se si dichiara il nome per l’enumerazione, non si verificherà alcun errore.

Se non dichiarato, devi usare un typedef :

 enum enum_name {RANDOM, IMMEDIATE, SEARCH} strategy; strategy = IMMEDIATE; 

Non visualizzerà un errore …

La mia costruzione preferita e sempre usata era sempre:

typedef enum MyBestEnum { / * abbastanza buono * / GOOD = 0, /* even better */ BETTER, /* divine */ BEST };

Credo che ciò eliminerà il tuo problema.

La risposta di Tarc è la migliore.

Gran parte della discussione sull’enum è un’aringa rossa.

Confronta questo snippet di codice: –

 int strategy; strategy = 1; void some_function(void) { } 

che dà

 error C2501: 'strategy' : missing storage-class or type specifiers error C2086: 'strategy' : redefinition 

con questo che compila senza problemi.

 int strategy; void some_function(void) { strategy = 1; } 

La strategy variabile deve essere impostata alla dichiarazione o all’interno di una funzione, ecc. Non è ansible scrivere software arbitrario – assegnazioni in particolare – nell’ambito globale.

Il fatto che abbia usato enum {RANDOM, IMMEDIATE, SEARCH} invece di int è rilevante solo nella misura in cui ha confuso le persone che non riescono a vedere oltre. I messaggi di errore di ridefinizione nella domanda mostrano che questo è ciò che l’autore ha sbagliato.

Quindi ora dovresti essere in grado di capire perché il primo dell’esempio qui sotto è sbagliato e gli altri tre sono a posto.

Esempio 1. SBAGLIATO!

 enum {RANDOM, IMMEDIATE, SEARCH} strategy; strategy = IMMEDIATE; void some_function(void) { } 

Esempio 2. A DESTRA.

 enum {RANDOM, IMMEDIATE, SEARCH} strategy = IMMEDIATE; void some_function(void) { } 

Esempio 3. A DESTRA.

 enum {RANDOM, IMMEDIATE, SEARCH} strategy; void some_function(void) { strategy = IMMEDIATE; } 

Esempio 4. A DESTRA.

 void some_function(void) { enum {RANDOM, IMMEDIATE, SEARCH} strategy; strategy = IMMEDIATE; } 

Se hai un programma funzionante dovresti essere in grado di incollare questi frammenti nel tuo programma e vedere che alcuni compilano e altri no.

Ho provato con gcc e ne ho ricavato per il mio bisogno sono stato costretto a usare l’ultima alternativa, per compilare senza errori.

stato typedef enum {a = 0, b = 1, c = 2} stato ;

 typedef enum state {a = 0, b = 1, c = 2} state; typedef enum state old; // New type, alias of the state type. typedef enum state new; // New type, alias of the state type. new now = a; old before = b; printf("State now = %d \n", now); printf("Sate before = %d \n\n", before);