Menu

Les constantes en C : const, #define et enum

Trois façons de nommer une valeur qui ne change jamais en C - le mot-clé const, les macros #define et les constantes d'énumération - ce que chacune est réellement, et laquelle choisir selon le cas.

Cette page contient des éditeurs exécutables - modifiez, exécutez et voyez la sortie instantanément.

Une constante est une valeur dotée d'un nom et de la promesse qu'elle ne changera pas. Le C vous offre trois mécanismes pour cela, et ce sont réellement des choses différentes sous le capot - l'une est une variable, l'autre une substitution de texte, la troisième un type entier.

Pourquoi nommer une valeur

Comparez ces deux lignes :

double area = 3.14159 * r * r;
double area = PI * r * r;

La seconde est meilleure pour trois raisons qui se manifestent toutes plus tard. Elle dit ce que le nombre signifie. Elle apparaît à un seul endroit, donc changer la précision est une modification plutôt qu'une recherche. Et une faute de frappe dans PI est une erreur de compilation, là où une faute dans 3.14195 est une mauvaise réponse.

Les nombres sans nom éparpillés dans le code s'appellent des nombres magiques, et les supprimer est l'une des améliorations les moins chères que vous puissiez apporter à un programme C.

const

Le mot-clé const marque une variable comme étant en lecture seule :

Décommentez l'affectation et le compilateur refuse : assignment of read-only variable 'PI'. Cette erreur à la construction est tout l'intérêt.

Une variable const est une vraie variable. Elle a un type, donc le compilateur vérifie comment vous l'utilisez. Elle obéit à la portée, donc un const dans une fonction ne fuit pas dehors. Elle a une adresse, vous pouvez donc pointer dessus. Et un débogueur peut vous montrer son nom et sa valeur.

Un const doit être initialisé au point de déclaration - il n'y a pas de seconde chance :

const int limit;       /* erreur (ou garbage pour toujours) : rien ne pourra l'affecter plus tard */
const int limit = 50;  /* correct */

#define

L'alternative du préprocesseur est une macro :

Ce n'est pas une variable. Avant que le compilateur ne tourne, le préprocesseur remplace chaque occurrence de PI dans le source par les caractères 3.14159265358979. Le compilateur ne voit jamais le nom - c'est exactement pourquoi un #define n'a pas de type et ne peut pas apparaître dans un débogueur.

Remarquez qu'il n'y a ni point-virgule ni =. Une macro est du texte brut, d'où cette erreur courante :

#define MAX_USERS 100;        /* notez le point-virgule */

int limit = MAX_USERS + 1;    /* se developpe en : int limit = 100; + 1;  -> erreur */

qui produit une erreur sur une ligne qui ne ressemble en rien à la définition. La convention de nommage en majuscules pour les macros existe précisément pour que les lecteurs sachent qu'une substitution a lieu.

Les macros s'écrivent conventionnellement en MAJUSCULES ; les variables const suivent généralement la même convention quand elles remplissent le même rôle.

Les constantes d'énumération

La troisième forme vous donne un ensemble d'entiers nommés :

Les valeurs commencent à 0 et augmentent de un tant que vous ne les affectez pas, donc MON vaut 0 et FRI vaut 4. Un enum { ... } anonyme est un idiome courant pour de simples constantes entières.

Les constantes d'énumération ont un vrai avantage sur les deux alternatives : ce sont des constantes entières de compilation que le compilateur comprend, et elles sont visibles du débogueur. L'histoire complète est sur les enums en C.

Laquelle utiliser

BesoinUtilisez
Une constante typée, portée, débogableconst
Une taille de tableau, une étiquette case, une largeur de champ de bitsenum ou #define
Une constante chaîne#define ou const char *
Une constante flottanteconst double
Un ensemble de valeurs entières liéesenum
Tout ce que le préprocesseur doit voir (#if, gardes d'inclusion)#define

Le choix par défaut devrait être const. Prenez #define quand la valeur doit exister avant la compilation, et enum quand il vous faut un entier de compilation ou un groupe nommé.

L'endroit où cela mord vraiment, ce sont les tailles de tableaux :

Un const int en C est une variable en lecture seule, pas une expression constante de compilation. Dans une fonction, C99 accepte int local[const_size] en en faisant un tableau de taille variable ; à portée fichier, dans une struct ou comme étiquette de case, il est rejeté net. enum et #define fonctionnent partout.

(C'est l'une des vraies différences avec le C++, où un const int est une expression constante. Le code qui circule entre les deux langages trébuche dessus.)

const avec les pointeurs

const et les pointeurs se combinent de trois façons, et les sens ne sont pas interchangeables. Lisez la déclaration depuis le nom vers l'extérieur :

const char *p;          /* p pointe vers des char qui ne doivent pas etre modifies */
char * const q;         /* q lui-meme ne peut pas etre repointe ; les char peuvent changer */
const char * const r;   /* ni le pointeur ni les char ne peuvent changer */

La forme const char * est celle que vous écrirez le plus, car c'est le bon type pour un paramètre de fonction qui lit une chaîne sans la modifier :

Ajouter const à un paramètre en lecture seule ne coûte rien et documente le contrat d'une façon que le compilateur fait respecter. Cela vaut la peine partout.

Les littéraux de chaîne sont de fait const

Un piège subtil que const existe pour attraper :

char *s = "hello";   /* C legal, mais s pointe dans de la memoire en lecture seule */
s[0] = 'H';          /* comportement indefini - generalement un plantage */

Les littéraux de chaîne vivent dans une section en lecture seule de l'exécutable. Écrire à travers ce pointeur provoque typiquement une erreur de segmentation. Déclarer le pointeur const char *s = "hello"; fait rejeter l'affectation par le compilateur au lieu de la laisser planter à l'exécution.

Si vous avez besoin d'une chaîne modifiable, copiez-la dans un tableau :

Questions fréquentes

Comment déclare-t-on une constante en C ?

Ajoutez const à une déclaration et donnez-lui une valeur : const double PI = 3.14159;. Le compilateur rejette alors toute tentative d'affectation. L'alternative plus ancienne est une macro du préprocesseur, #define PI 3.14159, qui fait plutôt une substitution de texte.

Quelle est la différence entre const et #define en C ?

const crée une véritable variable typée que le compilateur connaît : elle est vérifiée au niveau des types, apparaît dans le débogueur et obéit à la portée. #define est un pur remplacement de texte fait avant la compilation - sans type, sans portée, et impossible à inspecter pendant le débogage. Préférez const, sauf si vous avez besoin de la valeur dans un contexte exigeant une constante de compilation.

Une variable const peut-elle servir de taille de tableau en C ?

Pas pour un tableau de taille fixe à portée fichier. const int N = 10; int arr[N]; est un tableau de taille variable en C99 (autorisé dans une fonction, pas à portée fichier, ni dans une structure). Pour une vraie taille de compilation, utilisez #define N 10 ou enum { N = 10 };.

Que signifie const char *p ?

C'est un pointeur vers un char constant : vous pouvez changer où p pointe, mais pas le caractère pointé. char * const p est l'inverse - un pointeur constant vers un char modifiable. const char * const p verrouille les deux. Lisez la déclaration depuis le nom vers l'extérieur.

Coddy programming languages illustration

Apprendre à coder avec Coddy

COMMENCER