type énumération

spécificateur_d_énumération ::=

enum identificateuropt {liste-d-énumérateurs}

enum identificateuropt /*oublions cette possibilité */

liste-d-énumérateurs ::=

énumérateur

liste-d-énumérateurs, énumérateur

énumérateur ::=

identificateur

identificateur = expression-constante

Les déclarations suivantes :

enum arcenciel {rouge, jaune, vert, bleu, blanc } couleur ;

enum arcenciel tube1, tube2, tub 3 ;

introduisent 4 objets du type énumération arcenciel, et 5 noms (identificateurs) pour des valeurs.

En fait, C se démarque de la plupart des langages, en cela qu’arcenciel n’est pas vraiment un type à part. Les objets couleur, tube1, tube2, tube3, sont en fait des objets de type int.

On a seulement introduit des notations mnémoniques pour des valeurs entières. Les éléments de la liste ont des valeurs entières (0, 1, 2, …).

Dans l’exemple précédent, nous avons donc :

rouge == 0, jaune == 1, vert == 2, bleu == 3, blanc == 4

Le fait de pouvoir écrire :

int i = bleu + 1 ;

tube1 = 2 ; /* équivalent à tab2 = vert */

tube2 = 1025 ;

/* Une hérésie pour un programmeur de la plupart des lanages. On peut mettre n'importe quelle valeur entière dans  tube2 */

illustre bien le fait qu’arcenciel correspond au type int. L’identificateur bleu n’est qu’une notation désignant la valeur 3 (et on peut faire intervenir bleu dans n’importe quelle expression arithmétique).

Le langage C ne comporte aucune notation particulière pour obtenir la valeur qui suit (ou précède) une valeur de type énuméré.

En Ada, on aurait écrit : tub1 := arcenciel'succ(tube1) ;

En C, on écrit : tube1++ ; /* si simple */

Dans certains langages, on peut écrire :

for (i IN arcenciel) … /* si simple */

En C, il faut écrire :

for (int i = rouge ; i<= blanc, i++) … /* plus lourd */

Par défaut, les valeurs entières sont prises à partir de 0. On peut cependant associer à un nom une valeur entière quelconque (elle peut être négative) à l’aide du signe =. Les identificateurs qui suivent progressent par pas de 1 à partir de cette valeur :

enum jour_semaine {lundi = 1, mardi, mercredi, jeudi, vendredi, samedi} ;

donne :

mardi == 2, mercredi == 3, ... , samedi == 6 ;

Les noms doivent être différents, mais les valeurs associées n’ont pas besoin d’être différentes. Voici un exemple un peu bête à ne pas imiter.

enum nb_jour_mois { janvier = 31, fevrier = 28, fevrier_bisextile, mars = 31, avril = 30, ....}

Attention

Les identificateurs introduits pour désigner des valeurs polluent l’espace de noms. Il est interdit d’utiliser ces mêmes identificateurs pour désigner un autre objet ou une autre valeur d’un type énuméré. C’est stupide, mais c’est comme cela.

enum arcenciel {rouge, jaune, vert, bleu, blanc } couleur ;

enum {bleu, blanc, rouge} drapeau-français ; /* interdit, bleu, blanc, rouge sont déjà déclarés */

char * vert [] = "Michel Briand" ; /* vert existe déjà en temps que constante */

Règle de bonne utilisation des types énumérés

Faites comme si C fournissait de vrais types énumérés. Ne mettez dans un objet de type arcenciel que des valeurs définies dans la déclaration de type. Est-ce que l’exemple suivant qui consiste à utiliser le type énuméré arcenciel pour indexer un tableau et à initialiser ce tableau constitue une bonne utilisation?

int tab [blanc+1] ;

for (arcenciel i = rouge ; i <= blanc, i ++)

tab [i] = 0 ;

 

» Glossaire du langage C