194 votes

Const avant ou const après ?

Pour commencer, vous savez probablement que const peut être utilisé pour rendre les données d'un objet ou un pointeur non modifiable ou les deux.

const Object* obj; // can't change data
Object* const obj; // can't change pointer
const Object* const obj; // can't change data or pointer

Cependant, vous pouvez également utiliser la syntaxe :

Object const *obj; // same as const Object* obj;

La seule chose qui semble avoir de l'importance est le côté de l'astérisque où vous mettez le const mot-clé. Personnellement, je préfère mettre const à gauche du type pour spécifier que ses données ne sont pas modifiables, car je trouve que cela se lit mieux dans mon esprit de gauche à droite, mais quelle syntaxe est venue en premier ?

Plus important encore, pourquoi y a-t-il deux façons correctes de spécifier const et dans quelle situation préféreriez-vous ou auriez-vous besoin de l'un plutôt que de l'autre, le cas échéant ?

Edit :

Il semble donc qu'il s'agisse d'une décision arbitraire alors que la norme sur la façon dont les compilateurs doivent interpréter les choses a été rédigée bien avant ma naissance. Depuis const est appliqué à ce qui se trouve à gauche du mot-clé (par défaut ?) Je suppose qu'ils ont pensé qu'il n'y avait aucun mal à ajouter "raccourcis" pour appliquer les mots-clés et les qualificatifs de type d'une autre manière, au moins jusqu'à ce que la déclaration soit modifiée par l'analyse d'un * ou d'un & ...

C'était aussi le cas en C, je suppose ?

13 votes

Dans les macros, ajoutez toujours const après le type, par exemple #define MAKE_CONST(T) T const au lieu de #define MAKE_CONST(T) const T de sorte que MAKE_CONST(int *) s'étendra correctement à int * const au lieu de const int * .

14 votes

J'ai vu ces deux styles désignés par les termes "const est" et "const ouest".

35 votes

@TomAnderson mais en réalité cela devrait être "east const" et "const west".

139voto

Heath Hunnicutt Points 9801

pourquoi y a-t-il deux façons correctes de spécifier const et dans quelle situation préféreriez-vous ou auriez-vous besoin de l'un plutôt que de l'autre, le cas échéant ?

Essentiellement, la raison pour laquelle la position de const dans les spécificateurs avant un astérisque n'a pas d'importance est que la grammaire C a été définie de cette façon par Kernighan et Ritchie.

La raison pour laquelle ils ont défini la grammaire de cette manière était probablement que leur compilateur C analysait l'entrée de gauche à droite et finissait de traiter chaque jeton au fur et à mesure qu'il le consommait. Consommer le * change l'état de la déclaration actuelle en un type de pointeur. Rencontre avec const après * signifie que const est appliqué à la déclaration d'un pointeur ; s'il est rencontré avant la déclaration de l'indicateur * signifie que le qualificatif est appliqué aux données pointées.

Parce que le sens sémantique ne change pas si le const apparaît avant ou après les spécificateurs de type, il est accepté dans les deux cas.

Un cas similaire se présente lors de la déclaration de pointeurs de fonction, où :

  • void * function1(void) déclare une fonction qui renvoie void * ,

  • void (* function2)(void) déclare un pointeur de fonction à une fonction qui renvoie void .

Une fois encore, il convient de noter que la syntaxe du langage prend en charge un analyseur syntaxique de gauche à droite.

11 votes

Kernighan a coécrit le livre mais n'a pas participé à la conception de C, tout comme Ritchie.

0 votes

@TomZych OMG, Jusqu'au moment où je pensais que les deux K&R avaient écrit C, maintenant vous dites que K a seulement écrit le livre de C et pas C ?

19 votes

Je n'ai jamais pu me rappeler lequel est lequel. Grâce à votre explication, j'ai enfin la mnémotechnique pour m'en souvenir. Merci ! Avant * L'analyseur syntaxique du compilateur ne sait pas qu'il s'agit d'un pointeur, il s'agit donc d'un const pour une valeur de données. Après *, il est lié à un pointeur constant. C'est génial. Et finalement ça explique pourquoi je peux faire const char ainsi que char const .

100voto

horstforst Points 197

La règle est la suivante :

const s'applique à ce qu'il en reste. S'il n'y a rien à gauche, elle s'applique à la chose qui est à sa droite.

Je préfère utiliser const à droite de la chose qui doit être const, simplement parce que c'est la façon "originale" dont const est défini.

Mais je pense que c'est un point de vue très subjectif.

23 votes

Je préfère le mettre à gauche, mais je pense que le mettre à droite est plus logique. En C++, on lit généralement les types de droite à gauche, par exemple Object const * est un pointeur vers un objet constant. Si vous mettez le const à gauche, il serait lu comme un pointeur vers un objet qui est const, ce qui n'est pas très fluide.

0 votes

Il n'y a pas de telle "règle". Avez-vous une référence à quelque chose qui prétend qu'il existe une telle "règle" ?

1 votes

J'ai l'impression que la partie gauche est destinée à assurer la cohérence avec d'autres types de déclarations C (du point de vue informatique, ce n'est pas correct comme const n'est pas une classe de stockage, mais les gens ne sont pas des analyseurs syntaxiques).

89voto

Matt Davis Points 22019

Je préfère la deuxième syntaxe. Elle m'aide à garder la trace de "ce qui" est constant en lisant la déclaration de type de droite à gauche :

Object * const obj;        // read right-to-left:  const pointer to Object
Object const * obj;        // read right-to-left:  pointer to const Object
Object const * const obj;  // read right-to-left:  const pointer to const Object

4 votes

Exactement. Un "pointeur constant vers un objet constant" est Object const* const pas const const Object* . "Const" ne peut pas être à gauche, sauf dans le cas particulier où tant de gens l'aiment absolument. (Voir Heath ci-dessus.)

52voto

Bo Persson Points 42821

L'ordre des mots-clés dans une déclaration n'est pas si fixe que ça. Il existe de nombreuses alternatives au "seul véritable ordre". Par exemple

int long const long unsigned volatile i = 0;

ou devrait-il être

volatile unsigned long long int const i = 0;

? ?

34 votes

+1 pour une définition totalement confuse d'une simple variable :)

0 votes

@rubenvb - Oui, malheureusement, ils le sont. La grammaire dit simplement qu'un decl-specifier-seq est une séquence de decl-specifier s. Il n'y a pas d'ordre donné par la grammaire, et le nombre d'occurrences de chaque mot-clé est limité uniquement par certaines règles sémantiques (vous pouvez avoir un const mais deux long :-)

0 votes

@Bo : qu'en est-il unsigned ? Je pensais unsigned long etc. étaient des types à part entière, et que unsigned n'était pas vraiment un spécificateur à part entière ?

10voto

James Kanze Points 96599

La première règle est d'utiliser le format que vos normes de codage locales exigent. Ensuite, il faut mettre le const devant mène à une confusion sans fin lorsque confusion lorsque des typedefs sont impliqués, par ex :

typedef int* IntPtr;
const IntPtr p1;   // same as int* const p1;

Si votre standard de codage permet les typedef de pointeurs, alors il devrait vraiment devrait insister pour mettre le const après le type. Dans tous les cas, sauf sauf lorsqu'il est appliqué au type, le const doit suivre ce à quoi il s'applique. la cohérence plaide également en faveur du const après. Mais le codage local Mais les directives de codage local l'emportent sur tout cela ; la différence n'est normalement pas suffisamment importante pour revenir en arrière et modifier tout le code existant.

1 votes

Je pense que cela peut mettre en évidence la raison pour laquelle nous Ne le fais pas. ont des typedefs de pointeurs dans nos standards plutôt lâchement définis dans cette boutique.

2 votes

Ma politique (lorsque je peux décider seul) est de mettre la contrainte après (pour des raisons de cohérence) et de ne pas utiliser les typedefs pour les pointeurs (ou les typedefs en général) :-). Et BTW, string::iterator vs. string::const_iterator devrait probablement être pris en compte dans votre décision également. (Juste pour embrouiller les choses :-). Il n'y a pas de bonne réponse).

0 votes

Ah oui, j'aurais pu inclure le comportement de const std::string::const_iterator ainsi que pour faire bonne mesure ;)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X