Quelles sont les règles relatives à l'utilisation d'un trait de soulignement dans un identificateur C ++?

Oct 23 2008

Il est courant en C ++ de nommer les variables membres avec une sorte de préfixe pour indiquer le fait qu'elles sont des variables membres, plutôt que des variables ou des paramètres locaux. Si vous venez d'un fond MFC, vous utiliserez probablement m_foo. J'ai aussi vu myFoooccasionnellement.

C # (ou peut-être juste .NET) semble recommander d'utiliser simplement un trait de soulignement, comme dans _foo. Est-ce autorisé par la norme C ++?

Réponses

868 24revs,13users35%RogerPate Oct 23 2008 at 14:08

Les règles (qui n'ont pas changé en C ++ 11):

  • Réservé dans n'importe quelle étendue, y compris pour une utilisation en tant que macros d' implémentation :
    • identificateurs commençant par un trait de soulignement suivi immédiatement d'une lettre majuscule
    • identificateurs contenant des traits de soulignement adjacents (ou "double trait de soulignement")
  • Réservé dans l'espace de noms global:
    • identificateurs commençant par un trait de soulignement
  • De plus, tout ce qui se trouve dans l' stdespace de noms est réservé. (Vous êtes cependant autorisé à ajouter des spécialisations de modèle.)

À partir de la norme C ++ 2003:

17.4.3.1.2 Noms globaux [lib.global.names]

Certains ensembles de noms et signatures de fonctions sont toujours réservés à l'implémentation:

  • Chaque nom contenant un double trait de soulignement ( __) ou commençant par un trait de soulignement suivi d'une lettre majuscule (2.11) est réservé à l'implémentation pour toute utilisation.
  • Chaque nom commençant par un trait de soulignement est réservé à l'implémentation pour être utilisé comme nom dans l'espace de noms global. 165

165) Ces noms sont également réservés dans l'espace de noms ::std(17.4.3.1).

Parce que C ++ est basé sur le standard C (1.1 / 2, C ++ 03) et C99 est une référence normative (1.2 / 1, C ++ 03), ceux-ci s'appliquent également, à partir du standard C 1999:

7.1.3 Identifiants réservés

Chaque en-tête déclare ou définit tous les identifiants répertoriés dans son sous-paragraphe associé, et déclare ou définit éventuellement des identifiants listés dans son sous-paragraphe de directions de bibliothèque futur associé et des identifiants qui sont toujours réservés pour toute utilisation ou pour une utilisation comme identifiants de portée de fichier.

  • Tous les identifiants commençant par un trait de soulignement et une lettre majuscule ou un autre trait de soulignement sont toujours réservés pour toute utilisation.
  • Tous les identificateurs qui commencent par un trait de soulignement sont toujours réservés pour être utilisés comme identificateurs avec une portée de fichier dans les espaces de nom ordinaire et de balise.
  • Chaque nom de macro dans l'un des sous-paragraphes suivants (y compris les futures directions de bibliothèque) est réservé pour une utilisation comme spécifié si l'un de ses en-têtes associés est inclus; sauf indication contraire explicite (voir 7.1.4).
  • Tous les identifiants avec lien externe dans l'un des paragraphes suivants (y compris les futures directions de la bibliothèque) sont toujours réservés pour être utilisés comme identifiants avec lien externe. 154
  • Chaque identificateur avec la portée de fichier répertorié dans l'un des sous-paragraphes suivants (y compris les futures directions de la bibliothèque) est réservé pour une utilisation en tant que nom de macro et en tant qu'identifiant avec une portée de fichier dans le même espace de nom si l'un de ses en-têtes associés est inclus.

Aucun autre identifiant n'est réservé. Si le programme déclare ou définit un identifiant dans un contexte dans lequel il est réservé (autre que celui autorisé par 7.1.4), ou définit un identifiant réservé comme nom de macro, le comportement n'est pas défini.

Si le programme supprime (avec #undef) une définition de macro d'un identificateur dans le premier groupe répertorié ci-dessus, le comportement n'est pas défini.

154) La liste des identificateurs réservés avec une liaison externe comprend errno, math_errhandling, setjmpet va_end.

D'autres restrictions peuvent s'appliquer. Par exemple, le standard POSIX réserve de nombreux identifiants susceptibles de s'afficher en code normal:

  • Les noms commençant par une majuscule ont Esuivi un chiffre ou une lettre majuscule:
    • peut être utilisé pour des noms de code d'erreur supplémentaires.
  • Noms qui commencent par l'un isou l' autre tosuivi d'une lettre minuscule
    • peut être utilisé pour des fonctions de test et de conversion de caractères supplémentaires.
  • Noms commençant par LC_suivi d'une lettre majuscule
    • peut être utilisé pour des macros supplémentaires spécifiant des attributs de paramètres régionaux.
  • Les noms de toutes les fonctions mathématiques existantes avec le suffixe fou lsont réservés
    • pour les fonctions correspondantes qui fonctionnent sur des arguments flottants et longs, respectivement.
  • Les noms commençant par SIGsuivi d'une lettre majuscule sont réservés
    • pour des noms de signaux supplémentaires.
  • Les noms commençant par SIG_suivi d'une lettre majuscule sont réservés
    • pour des actions de signal supplémentaires.
  • Les noms commençant par str, memou wcssuivis d'une lettre minuscule sont réservés
    • pour des fonctions supplémentaires de chaîne et de tableau.
  • Les noms commençant par PRIou SCNsuivis d'une lettre minuscule ou Xsont réservés
    • pour des macros de spécification de format supplémentaires
  • Les noms qui se terminent par _tsont réservés
    • pour des noms de types supplémentaires.

Bien que l'utilisation de ces noms à vos propres fins actuellement ne pose pas de problème, ils soulèvent la possibilité d'un conflit avec les futures versions de cette norme.


Personnellement, je ne commence pas les identifiants avec des traits de soulignement. Nouvel ajout à ma règle: n'utilisez pas de traits de soulignement doubles, ce qui est facile car j'utilise rarement des traits de soulignement.

Après avoir fait des recherches sur cet article, je ne termine plus mes identifiants par _tcar cela est réservé par le standard POSIX.

La règle sur tout identifiant se terminant par _tm'a beaucoup surpris. Je pense que c'est un standard POSIX (pas encore sûr) à la recherche de clarifications et de chapitres et versets officiels. Ceci est tiré du manuel GNU libtool , listant les noms réservés.

CesarB a fourni le lien suivant vers les symboles réservés POSIX 2004 et note «que de nombreux autres préfixes et suffixes réservés ... peuvent y être trouvés». Les symboles réservés POSIX 2008 sont définis ici. Les restrictions sont un peu plus nuancées que celles ci-dessus.

202 paercebal Oct 23 2008 at 14:27

Les règles pour éviter la collision des noms sont à la fois dans le standard C ++ (voir le livre Stroustrup) et mentionnées par les gourous du C ++ (Sutter, etc.).

Règle personnelle

Parce que je ne voulais pas traiter de cas, et que je voulais une règle simple, j'ai conçu une règle personnelle à la fois simple et correcte:

Lorsque vous nommez un symbole, vous éviterez la collision avec les bibliothèques compilateur / OS / standard si vous:

  • ne jamais commencer un symbole avec un trait de soulignement
  • ne nommez jamais un symbole avec deux traits de soulignement consécutifs à l'intérieur.

Bien sûr, placer votre code dans un espace de noms unique permet également d'éviter les collisions (mais ne protégera pas contre les macros maléfiques)

Quelques exemples

(J'utilise des macros car ce sont les symboles C / C ++ qui polluent le plus le code, mais cela pourrait être n'importe quoi, du nom de la variable au nom de la classe)

#define _WRONG
#define __WRONG_AGAIN
#define RIGHT_
#define WRONG__WRONG
#define RIGHT_RIGHT
#define RIGHT_x_RIGHT

Extraits du brouillon C ++ 0x

À partir du fichier n3242.pdf (je m'attends à ce que le texte standard final soit similaire):

17.6.3.3.2 Noms globaux [global.names]

Certains ensembles de noms et signatures de fonctions sont toujours réservés à l'implémentation:

- Chaque nom qui contient un double trait de soulignement _ _ ou qui commence par un trait de soulignement suivi d'une lettre majuscule (2.12) est réservé à l'implémentation pour toute utilisation.

- Chaque nom commençant par un trait de soulignement est réservé à l'implémentation pour être utilisé comme nom dans l'espace de noms global.

Mais aussi:

17.6.3.3.5 Suffixes littéraux définis par l'utilisateur [usrlit.suffix]

Les identificateurs de suffixe littéral qui ne commencent pas par un trait de soulignement sont réservés pour une future normalisation.

Cette dernière clause est déroutante, sauf si vous considérez qu'un nom commençant par un trait de soulignement et suivi d'une lettre minuscule serait OK s'il n'est pas défini dans l'espace de noms global ...

40 RogerLipscombe Oct 23 2008 at 14:06

Depuis MSDN :

L'utilisation de deux caractères de soulignement séquentiels (__) au début d'un identificateur, ou d'un simple trait de soulignement suivi d'une majuscule, est réservée aux implémentations C ++ dans toutes les étendues. Vous devez éviter d'utiliser un trait de soulignement avant suivi d'une lettre minuscule pour les noms avec une portée de fichier en raison de conflits possibles avec les identificateurs réservés actuels ou futurs.

Cela signifie que vous pouvez utiliser un seul trait de soulignement comme préfixe de variable membre, à condition qu'il soit suivi d'une lettre minuscule.

Ceci est apparemment tiré de la section 17.4.3.1.2 du standard C ++, mais je ne trouve pas de source originale pour le standard complet en ligne.

Voir aussi cette question .

25 MaxLybbert Nov 15 2008 at 03:03

Quant à l'autre partie de la question, il est courant de mettre le trait de soulignement à la fin du nom de la variable pour ne pas entrer en conflit avec quoi que ce soit d'interne.

Je fais cela même à l'intérieur des classes et des espaces de noms car je n'ai plus qu'à me souvenir d'une règle (par rapport à "à la fin du nom dans la portée globale, et au début du nom partout ailleurs").

1 JohnMillikin Oct 23 2008 at 14:05

Oui, les traits de soulignement peuvent être utilisés n'importe où dans un identifiant. Je crois que les règles sont les suivantes: n'importe laquelle de az, AZ, _ dans le premier caractère et celles + 0-9 pour les caractères suivants.

Les préfixes de soulignement sont courants dans le code C - un seul trait de soulignement signifie «privé», et les doubles traits de soulignement sont généralement réservés à l'usage du compilateur.