web-dev-qa-db-fra.com

Comment définir un type énuméré (enum) en C?

Je ne sais pas quelle est la syntaxe appropriée pour utiliser les énumérations. J'ai le code suivant:

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

Mais cela ne compile pas, avec l'erreur suivante:

error: conflicting types for ‘strategy’
error: previous declaration of ‘strategy’ was here

Qu'est-ce que je fais mal?

253
lindelof

Déclarer une variable enum se fait comme ceci:

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

Cependant, vous pouvez utiliser une variable typedef pour raccourcir les déclarations de variable, comme ceci:

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

Avoir une convention de nommage pour distinguer les types et les variables est une bonne idée:

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

Cela vaut la peine de souligner que vous n'avez pas besoin a typedef. Vous pouvez simplement le faire comme suit

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

C'est une question de style si vous préférez typedef. Sans lui, si vous souhaitez faire référence au type d'énumération, vous devez utiliser enum strategy. Avec cela, vous pouvez simplement dire strategy.

Les deux manières ont leurs avantages et inconvénients. L'un est plus verbeux, mais conserve les identifiants de type dans l'espace de noms de balises où ils ne seront pas en conflit avec les identifiants ordinaires (pensez à struct stat et à la fonction stat: ils ne sont pas en conflit non plus) et où vous voyez immédiatement qu'il s'agit d'un type . L'autre est plus court, mais introduit les identificateurs de type dans l'espace de noms ordinaire. 

441

Vous essayez de déclarer strategy deux fois, et c’est pourquoi vous obtenez l’erreur ci-dessus. Ce qui suit fonctionne sans aucune plainte (compilé avec gcc -ansi -pendantic -Wall):

#include <stdio.h>

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

int main(int argc, char** argv){
    printf("strategy: %d\n", strategy);

    return 0;
}

Si au lieu de ce qui précède, la deuxième ligne a été modifiée en:

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

Parmi les avertissements, vous pouvez facilement voir votre erreur:

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

Le compilateur a donc pris strategy = IMMEDIATE pour la déclaration d'une variable appelée strategy avec le type par défaut int, mais il existait déjà une déclaration précédente d'une variable portant ce nom.

Toutefois, si vous avez placé l'affectation dans la fonction main(), il s'agirait d'un code valide:

#include <stdio.h>

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

int main(int argc, char** argv){
    strategy=SEARCH;
    printf("strategy: %d\n", strategy);

    return 0;
}
53
Tarc

Quand tu dis

enum {RANDOM, IMMEDIATE, SEARCH} strategy;

vous créez une seule variable d'instance, appelée "stratégie" d'une énumération sans nom. Ce n'est pas une chose très utile à faire - vous avez besoin d'un typedef:

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

Comme écrit, il n'y a rien de mal avec votre code. Êtes-vous sûr de ne pas avoir fait quelque chose comme

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

Sur quelles lignes pointent les messages d'erreur? Quand on dit "la déclaration de stratégie précédente était ici", qu'est-ce que "ici" et que montre-t-il? 

13
John Bode

@ThoAppelsin dans son commentaire à la question postée est juste. L'extrait de code publié dans la question est valide et sans erreur. L'erreur que vous avez doit être due à une autre syntaxe incorrecte à n'importe quel endroit de votre fichier source c. enum{a,b,c}; définit trois constantes symboliques (a, b et c) qui sont des entiers avec les valeurs 0, 1 et 2 respectivement, mais lorsque nous utilisons enum c'est parce que nous ne nous soucions pas de la valeur entière spécifique, nous nous soucions davantage du nom de la constante symbolique. Cela signifie que vous pouvez avoir ceci:

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

et ceci produira 1.

Ce sera également valide:

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

et produira la même chose que précédemment.

Si tu fais ça:

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

vous aurez une erreur, mais si vous faites ceci:

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

vous n'aurez aucune erreur.

tu peux le faire:

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

et aa sera une variable entière avec la valeur 0. mais vous pouvez aussi faire ceci:

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

et aura le même effet (c’est-à-dire que aa sera une int avec une valeur 0). 

vous pouvez aussi faire ceci:

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

et aa sera int avec la valeur 7.

comme vous ne pouvez pas répéter la définition de constante symbolique avec l'utilisation de enum, comme je l'ai dit précédemment, vous devez utiliser des balises si vous souhaitez déclarer int vars avec l'utilisation de enum:

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

l'utilisation de typedef permet d'éviter d'écrire chaque fois enum tag1 pour définir une variable. Avec typedef, vous pouvez simplement taper Tag1:

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

Vous pouvez aussi avoir:

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

La dernière chose à dire, c’est que puisque nous parlons de constantes symboliques définies, il est préférable d’utiliser des lettres majuscules lorsque vous utilisez enum, c’est-à-dire:

enum {A,B,C};

au lieu de 

enum {a,b,c};
11
roggc

Il convient de noter que en C++ vous pouvez utiliser "enum" pour définir un nouveau type sans avoir besoin d'une instruction typedef. 

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

Je trouve cette approche beaucoup plus conviviale.

[modifier - statut C++ clarifié - je l'avais à l'origine, puis je l'ai supprimé!]

10
Roddy

Il semble y avoir une confusion à propos de la déclaration.

Quand strategycentre avant {RANDOM, IMMEDIATE, SEARCH} comme ci-dessous,

enum strategy {RANDOM, IMMEDIATE, SEARCH};

vous créez un nouveau type nommé enum strategy. Cependant, lors de la déclaration de la variable, vous devez utiliser enum strategy lui-même. Vous ne pouvez pas simplement utiliser strategy. Donc, ce qui suit est invalide.

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

Alors que, ce qui suit est valide

enum strategy {RANDOM, IMMEDIATE, SEARCH};

enum strategy queen = RANDOM;
enum strategy king = SEARCH;
enum strategy pawn[100];

Lorsque strategy vient après {RANDOM, IMMEDIATE, SEARCH}, vous créez une énumération anonyme, puis vous déclarez que strategy est une variable de ce type.

Alors maintenant, vous pouvez faire quelque chose comme

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

Cependant, vous ne pouvez déclarer aucune autre variable de type enum {RANDOM, IMMEDIATE, SEARCH} car vous ne l'avez jamais nommée. Donc ce qui suit est invalide

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

Vous pouvez aussi combiner les deux définitions

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

a = RANDOM;
b = SEARCH;
enum strategy c = IMMEDIATE;

Typedef, comme indiqué précédemment, est utilisé pour créer une déclaration de variable plus courte.

typedef enum {RANDOM, IMMEDIATE, SEARCH} strategy;

Vous avez maintenant dit au compilateur que enum {RANDOM, IMMEDIATE, SEARCH} est synonyme de strategy. Alors maintenant, vous pouvez utiliser librement strategy comme type de variable. Vous n'avez plus besoin de taper enum strategy. Ce qui suit est valide maintenant

strategy x = RANDOM;

Vous pouvez également combiner Typedef avec le nom d’énum pour obtenir

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

L'utilisation de cette méthode présente peu d'avantages, mis à part le fait que vous pouvez maintenant utiliser strategy et enum strategyName de façon interchangeable.

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

enum strategyName a = RANDOM;
strategy b = SEARCH;
6
Confuse

Si vous déclarez le nom pour l'énumération, aucune erreur ne se produira.

Si non déclaré, vous devez utiliser une typedef:

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

Il n'y aura pas d'erreur.

2
user3135028

Ma construction préférée et uniquement utilisée a toujours été:

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

Je crois que cela va résoudre votre problème que vous avez. Utiliser un nouveau type est de mon point de vue une bonne option.

1
Sany

La réponse de Tarc est la meilleure.

Une grande partie de la discussion enum est un hareng rouge.

Comparez cet extrait de code: -

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

qui donne 

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

avec celui-ci qui compile sans problème.

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

La variable strategy doit être définie lors de la déclaration ou à l'intérieur d'une fonction, etc. Vous ne pouvez pas écrire de logiciel arbitraire - des assignations en particulier - à la portée globale.

Le fait qu’il ait utilisé enum {RANDOM, IMMEDIATE, SEARCH} au lieu de int n’est pertinent que dans la mesure où il a confondu des personnes qui ne peuvent voir au-delà . l'auteur a mal agi.

Alors maintenant, vous devriez pouvoir voir pourquoi le premier de l'exemple ci-dessous est faux et les trois autres vont bien.

Exemple 1. FAUX!

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

Exemple 2. DROIT.

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

Exemple 3. DROIT.

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

Exemple 4. DROIT.

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

Si vous avez un programme opérationnel, vous devriez simplement pouvoir coller ces extraits dans votre programme et voir que certains compilent et d'autres non.

1
user3070485

J'ai essayé avec gcc et, pour mon besoin, j'étais obligé d'utiliser la dernière alternative, de compiler sans erreur. 

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

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);
0
gg cg