Les énumérations (enum) en C
Une énumération est un type de données défini par l'utilisateur qui permet d'associer des noms symboliques à des constantes entières. Elle améliore la lisibilité du code en remplaçant des valeurs numériques arbitraires par des identifiants expressifs.
enum) Un enum est un type entier dont les valeurs possibles sont représentées par des constantes nommées (les énumérateurs). Par défaut, le premier énumérateur vaut 0, chaque suivant valant le précédent + 1. Les valeurs peuvent être redéfinies explicitement.enum Cenum NomType { const1, const2, ..., constN };
/* Valeurs explicites (optionnel) */
enum NomType { const1 = val1, const2 = val2, ..., constN = valN };
/* Déclaration de variable */
enum NomType variable;| Aspect | enum | #define | const int |
|---|---|---|---|
| Type défini | Oui — type distinct | Non — simple substitution textuelle | Oui |
| Regroupement logique | Oui — toutes les constantes dans un type | Non | Non |
| Débogage | Visible dans le débogueur | Invisible (préprocesseur) | Visible |
| Vérification de type | Oui (en C++) | Non | Oui |
1. Déclarer un type et des variables enum
Comme pour struct, déclarer un enum crée uniquement un nouveau type — aucune mémoire n'est réservée. Il faut ensuite déclarer une variable de ce type.
| Méthode | Code |
|---|---|
| Déclaration séparée | enum boolean { Vrai, Faux }; |
| Déclaration combinée | enum boolean { Vrai, Faux } etat; |
Avec typedef | typedef enum { Vrai, Faux } boolean; |
Exemple n°1 — enum des jours de la semaine
#include <stdio.h>
enum semaine { dimanche, lundi, mardi, mercredi, jeudi, vendredi, samedi };
/* 0 1 2 3 4 5 6 */
int main(void)
{
enum semaine jour;
jour = mercredi; /* équivaut à : jour = 3 */
printf("Numéro du jour : %d\n", jour);
printf("Numéro du jour suivant : %d\n", jour + 1);
return 0;
}Numéro du jour : 3 Numéro du jour suivant : 4
typedef enum pour simplifier Avec typedef, plus besoin de répéter le mot-clé enumà chaque déclaration de variable :typedef enum { dimanche, lundi, mardi, mercredi, jeudi, vendredi, samedi } Semaine;
Semaine jour = mercredi; /* sans répéter "enum" */2. Valeurs des énumérateurs
a. Valeurs par défaut
Sans initialisation explicite, les énumérateurs reçoivent des valeurs entières consécutives à partir de 0.
Exemple n°2 — Valeurs implicites à partir de 0
#include <stdio.h>
enum semaine { dimanche, lundi, mardi, mercredi, jeudi, vendredi, samedi };
int main(void)
{
printf("dimanche = %d\n", dimanche); /* 0 */
printf("lundi = %d\n", lundi); /* 1 */
printf("samedi = %d\n", samedi); /* 6 */
return 0;
}dimanche = 0 lundi = 1 samedi = 6
b. Valeurs explicites
On peut affecter des valeurs explicites à certains (ou tous) les énumérateurs. Les suivants non spécifiés reprennent à partir du dernier + 1.
Exemple n°3 — Mélange de valeurs explicites et implicites
#include <stdio.h>
enum etat {
pret = 0,
elu = 1,
bloque = 2,
zombie = 3
};
/* Variante : numérotation par puissances de 2 (drapeaux binaires) */
enum droits {
lecture = 1, /* 001 */
ecriture = 2, /* 010 */
execution = 4 /* 100 */
};
int main(void)
{
enum etat p1 = elu;
printf("État de p1 : %d\n", p1);
printf("Taille de p1 : %lu octets\n", sizeof(p1));
/* Combinaison de drapeaux par OR binaire */
int acces = lecture | ecriture;
printf("Accès (lire+écrire) : %d\n", acces);
return 0;
}État de p1 : 1 Taille de p1 : 4 octets Accès (lire+écrire) : 3
enum En C, un enum est stocké comme un int — il occupe donc généralement 4 octets, quelle que soit la valeur des énumérateurs. C'est ce qui en fait un choix efficace pour les drapeaux (flags) et les états.c. Deux énumérateurs peuvent partager la même valeur
Exemple n°4 — Alias entre énumérateurs
#include <stdio.h>
enum etat {
pret = 0,
elu = 0, /* alias de pret */
bloque = 1
};
int main(void)
{
printf("pret = %d\n", pret);
printf("elu = %d\n", elu);
printf("bloque = %d\n", bloque);
printf("pret == elu ? %s\n", (pret == elu) ? "Oui" : "Non");
return 0;
}pret = 0 elu = 0 bloque = 1 pret == elu ? Oui
3. enum avec switch
L'usage le plus courant d'un enum est dans une instruction switch : chaque case correspond à un énumérateur nommé, ce qui rend le code immédiatement compréhensible.
Exemple n°5 — Gestion d'états avec enum et switch
#include <stdio.h>
typedef enum {
PRET = 0,
ELU = 1,
BLOQUE = 2,
ZOMBIE = 3
} EtatProcessus;
void afficher_etat(EtatProcessus e)
{
switch (e)
{
case PRET : printf("Processus prêt\n"); break;
case ELU : printf("Processus élu\n"); break;
case BLOQUE : printf("Processus bloqué\n"); break;
case ZOMBIE : printf("Processus zombie\n"); break;
default : printf("État inconnu\n");
}
}
int main(void)
{
EtatProcessus p = BLOQUE;
afficher_etat(p);
p = ELU;
afficher_etat(p);
return 0;
}Processus bloqué Processus élu
4. Règles importantes
a. Unicité dans la portée
Tous les énumérateurs doivent avoir des noms uniques dans leur portée. Deux enum différents ne peuvent pas avoir un énumérateur de même nom dans la même portée.
Exemple n°6 — Conflit de noms entre deux enum
enum state { working, failed };
enum result { failed, passed }; /* erreur : "failed" redéfini */
int main(void) { return 0; }error: redefinition of enumerator 'failed'
enum définis dans la même portée partagent un nom d'énumérateur, le compilateur signale une erreur. Solutions : renommer les énumérateurs pour les rendre uniques (convention : préfixer par le nom du type) ou utiliser des portées distinctes (namespaceen C++)./* Convention de nommage recommandée en C */
enum State { STATE_WORKING, STATE_FAILED };
enum Result { RESULT_FAILED, RESULT_PASSED };b. Les valeurs doivent être des constantes entières
int x = 5;
enum T { A = x }; /* erreur — x n'est pas une constante */
enum T { B = 3.14 }; /* erreur — valeur flottante */
enum T { C = 2 + 3 }; /* autorisé — expression constante */Récapitulatif
| Concept | Règle / Syntaxe | Point clé |
|---|---|---|
| Déclaration | enum Nom { A, B, C }; | Crée un type — pas de mémoire allouée |
| Valeurs par défaut | A=0, B=1, C=2… | Consécutives à partir de 0 |
| Valeurs explicites | enum Nom { A=5, B, C=10 }; | B vaut 6 (précédent + 1) |
| Taille | sizeof(enum Nom) = 4 | Stocké comme un int |
| Alias autorisé | A=0, B=0 | Deux noms peuvent partager la même valeur |
| Unicité des noms | Noms uniques dans la portée | Conflit → erreur de compilation |
| Convention | PREFIX_NOM | Évite les conflits entre plusieurs enum |
| Cas d'usage principal | switch(var) { case A: … } | Code lisible sans constantes numériques brutes |
Discussion (0)
Soyez le premier à laisser un commentaire !
Laisser un commentaire
Votre commentaire sera visible après modération.