web-dev-qa-db-fra.com

Pourquoi la plupart des développeurs C utilisent-ils define au lieu de const?

Dans de nombreux programmes, un #define sert le même objectif qu'une constante. Par exemple.

#define FIELD_WIDTH 10
const int fieldWidth = 10;

Je vois généralement le premier formulaire préféré à l'autre, en s'appuyant sur le pré-processeur pour gérer ce qui est essentiellement une décision d'application. Y a-t-il une raison à cette tradition?

89
C. Ross

Il y a une raison très solide à cela: const en C ne signifie pas que quelque chose est constant. Cela signifie simplement qu'une variable est en lecture seule.

Dans les endroits où le compilateur requiert une vraie constante (comme pour les tailles de tableau pour les tableaux non VLA), l'utilisation d'une variable const, telle que fieldWidth n'est tout simplement pas possible.

154

Ils sont différents.

const n'est qu'un qualificatif, qui indique qu'une variable ne peut pas être modifiée au moment de l'exécution. Mais toutes les autres caractéristiques de la variable persistent: elle a alloué du stockage, et ce stockage peut être adressé. Le code ne le traite donc pas uniquement comme un littéral, mais fait référence à la variable en accédant à l'emplacement de mémoire spécifié (sauf s'il s'agit de static const, il peut ensuite être optimisé) et charger sa valeur au moment de l'exécution. Et comme une variable const a alloué du stockage, si vous l'ajoutez à un en-tête et l'incluez dans plusieurs sources C, vous obtiendrez une erreur de liaison "définition de symboles multiples" sauf si vous la marquez comme extern. Et dans ce cas, le compilateur ne peut pas optimiser le code par rapport à sa valeur réelle (sauf si l'optimisation globale est activée).

#define remplace simplement un nom par sa valeur. De plus, un #define 'd constante peut être utilisée dans le préprocesseur: vous pouvez l'utiliser avec #ifdef pour effectuer une compilation conditionnelle en fonction de sa valeur, ou utilisez l'opérateur de chaîne # pour obtenir une chaîne avec sa valeur. Et comme le compilateur connaît sa valeur au moment de la compilation, il peut optimiser le code en fonction de cette valeur.

Par exemple:

#define SCALE 1

...

scaled_x = x * SCALE;

Lorsque SCALE est défini comme 1 le compilateur peut éliminer la multiplication car il sait que x * 1 == x, mais si SCALE est un (extern) const, il devra générer du code pour récupérer la valeur et effectuer la multiplication car la valeur ne sera connue que l'étape de liaison. (extern est nécessaire pour utiliser la constante de plusieurs fichiers source.)

Un équivalent plus proche de l'utilisation de #define utilise des énumérations:

enum dummy_enum {
   constant_value = 10010
};

Mais cela est limité aux valeurs entières et n'a pas les avantages de #define, il n'est donc pas largement utilisé.

const est utile lorsque vous devez importer une valeur constante à partir d'une bibliothèque dans laquelle elle a été compilée. Ou si elle est utilisée avec des pointeurs. Ou s'il s'agit d'un tableau de valeurs constantes accessibles via une valeur d'index variable. Sinon, const n'a aucun avantage sur #define.

21
Vovanium

La raison en est que la plupart du temps, vous voulez une constante, pas une variable qualifiée const. Les deux ne sont pas à distance les mêmes dans le langage C. Par exemple, les variables ne sont pas valides dans le cadre des initialiseurs pour les objets static- durée de stockage, en tant que dimensions de tableau non-vla (par exemple, la taille d'un tableau dans une structure ou tout tableau antérieur à C99).

13
R..

Développant un peu la réponse de R: fieldWidth n'est pas un expression constante; c'est une variable qualifiée const. Son valeur n'est pas établi avant l'exécution, il ne peut donc pas être utilisé lorsqu'une expression constante de compilation est requise (comme dans une déclaration de tableau ou une étiquette de casse dans un switch déclaration, etc.).

Comparer avec la macro FIELD_WIDTH, qui après le prétraitement se développe en l'expression constante 10; cette valeur est connue au moment de la compilation, elle peut donc être utilisée pour les dimensions de tableau, les étiquettes de cas, etc.

8
John Bode

Pour ajouter à la réponse de R. et Bart: il n'y a qu'une seule façon de définir des constantes de temps de compilation symboliques dans les constantes de type énumération C :. La norme impose que ceux-ci soient de type int. Personnellement, j'écrirais votre exemple comme

enum { fieldWidth = 10 };

Mais je suppose que le goût diffère beaucoup parmi les programmeurs C à ce sujet.

6
Jens Gustedt

Bien qu'un const int ne soit pas toujours approprié, une énumération fonctionnera généralement comme un substitut à #define si vous définissez quelque chose comme étant une valeur intégrale. C'est en fait ma préférence dans un tel cas.

enum { FIELD_WIDTH = 16384 };
char buf[FIELD_WIDTH];

En C++, c'est un énorme avantage car vous pouvez étendre votre énumération dans une classe ou un espace de noms, alors que vous ne pouvez pas étendre un #define.

En C, vous n'avez pas d'espaces de noms et vous ne pouvez pas étendre une énumération à l'intérieur d'une structure, et je ne suis même pas sûr que vous obtenez la sécurité de type, donc je ne vois aucun avantage majeur, bien que peut-être un programmeur C me le fasse remarquer .

4
CashCow

Selon K&R (2e édition, page 211), "les propriétés const et volatiles sont nouvelles avec la norme ANSI". Cela peut impliquer que le code ANSI vraiment ancien n'avait pas ces mots-clés et c'est vraiment une question de tradition. De plus, il indique qu'un compilateur doit détecter les tentatives de modification des variables const mais à part cela, il peut ignorer ces qualificatifs. Je pense que cela signifie que certains compilateurs peuvent ne pas optimiser le code contenant la variable const à représenter comme valeur intermédiaire dans le code machine (comme le fait #define) et cela pourrait coûter plus de temps pour accéder à la mémoire distante et affecter les performances.

2
Shlomi Loubaton

Certains compilateurs C stockent toutes les variables const dans le binaire, qui si elles préparent ne grande liste de coefficients peut utiliser une énorme quantité d'espace dans le monde embarqué.

Inversement: l'utilisation de const permet de flasher un programme existant pour modifier des paramètres spécifiques.

1
Nick T

La meilleure façon de définir des constantes numériques en C est d'utiliser enum. Lisez le chapitre correspondant du langage de programmation C de K&R, page 39.

0
esoriano