tag Quelles sont les règles d'utilisation d'un trait de soulignement dans un identifiant C++?




nouvelle couleur tag mac (4)

Comme pour 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 quelque chose d'interne.

Je le fais même à l'intérieur des classes et des espaces de noms parce que je dois seulement me souvenir d'une règle (par rapport à "à la fin du nom dans la portée globale, et le début du nom partout ailleurs").

Il est courant en C ++ de nommer les variables membres avec un type de préfixe pour indiquer le fait qu'il s'agit de variables membres plutôt que de variables ou de paramètres locaux. Si vous venez d'un arrière-plan MFC, vous utiliserez probablement m_foo . J'ai aussi vu myFoo temps en temps.

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


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

  • Réservé dans toute portée, y compris pour une utilisation en tant que macros d'implémentation:
    • identifiants commençant par un trait de soulignement suivi immédiatement d'une lettre majuscule
    • identifiants contenant des traits de soulignement adjacents (ou "double underscore")
  • Réservé dans l'espace de noms global:
    • identifiants commençant par un soulignement
  • En outre, tout dans l'espace de noms std est réservé. (Vous êtes autorisé à ajouter des spécialisations de modèle, cependant.)

De la norme C ++ 2003:

17.4.3.1.2 Noms globaux [lib.global.names]

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

  • Chaque nom qui contient un trait de soulignement double ( __ ) ou commence par un trait de soulignement suivi d'une lettre majuscule (2.11) est réservé à l'implémentation pour toute utilisation.
  • Chaque nom qui commence 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 namespace ::std (17.4.3.1).

Parce que C ++ est basé sur la norme C (1.1 / 2, C ++ 03) et que C99 est une référence normative (1.2 / 1, C ++ 03), ils s'appliquent également, à partir de la norme C 1999:

7.1.3 Identifiants réservés

Chaque en-tête déclare ou définit tous les identificateurs énumérés dans son sous-paragraphe associé et déclare ou définit facultativement les identificateurs énumérés dans le sous-paragraphe et les identifiants de directions de bibliothèque associés qui sont toujours réservés à toute utilisation ou utilisation en tant qu'identifiants de portée de fichier.

  • Tous les identifiants commençant par un trait de soulignement et une lettre majuscule ou un autre caractère de soulignement sont toujours réservés à toute utilisation.
  • Tous les identifiants commençant par un trait de soulignement sont toujours réservés à l'utilisation en tant qu'identifiants avec la portée du fichier dans les espaces de noms ordinaires et de balises.
  • Chaque nom de macro dans l'un des sous-paragraphes suivants (y compris les futures directions de la bibliothèque) est réservé à l'utilisation spécifiée si l'un de ses en-têtes associés est inclus; sauf mention contraire explicite (voir 7.1.4).
  • Tous les identifiants avec liaison externe dans l'un des sous-paragraphes suivants (y compris les futures directions de la bibliothèque) sont toujours réservés à l'utilisation en tant qu'identifiants avec liaison externe. 154
  • Chaque identificateur avec l'étendue de fichier répertoriée dans l'un des sous-paragraphes suivants (y compris les futures directions de la bibliothèque) est réservé à l'utilisation en tant que nom de macro et en tant qu'identificateur avec la portée de fichier dans le même espace de noms.

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 ) toute définition de macro d'un identifiant dans le premier groupe listé ci-dessus, le comportement n'est pas défini.

154) La liste des identifiants réservés avec un lien externe comprend errno , math_errhandling , setjmp et va_end .

D'autres restrictions peuvent s'appliquer. Par exemple, la norme POSIX réserve beaucoup d'identifiants susceptibles d'apparaître dans le code normal:

  • Les noms commençant par un E majuscule ont suivi un chiffre ou une majuscule:
    • peut être utilisé pour des noms de code d'erreur supplémentaires.
  • Les noms commençant par is ou sont suivis 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 régionaux.
  • Les noms de toutes les fonctions mathématiques existantes suffixées avec f ou l sont réservés
    • pour les fonctions correspondantes qui fonctionnent respectivement sur les arguments float et long double.
  • Les noms commençant par SIG suivi d'une lettre majuscule sont réservés
    • pour les 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 , mem ou wcs suivi d'une lettre minuscule sont réservés
    • pour des fonctions de chaîne et de tableau supplémentaires.
  • Les noms commençant par PRI ou SCN suivi par une lettre minuscule ou X sont réservés
    • pour les macros de spécification de format supplémentaires
  • Les noms qui se terminent par _t sont réservés
    • pour les noms de types supplémentaires.

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

Personnellement, je ne démarre pas les identifiants avec des traits de soulignement. Nouvel ajout à ma règle: N'utilisez pas de doubles underscores n'importe où, ce qui est facile car j'utilise rarement le underscore.

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

La règle concernant tout identifiant se terminant par _t m'a beaucoup surpris. Je pense que c'est une norme POSIX (pas encore sûre) à la recherche de clarifications et de chapitres et de versets officiels. C'est à partir du manuel GNU libtool , listant les noms réservés.

CesarB a fourni le lien suivant aux symboles réservés de opengroup.org/onlinepubs/009695399/functions/xsh_chap02_02.html et note que «beaucoup d'autres préfixes et suffixes réservés ... peuvent être trouvés là». Les symboles réservés POSIX 2008 sont définis ici. Les restrictions sont un peu plus nuancées que celles ci-dessus.


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

Règle personnelle

Parce que je ne voulais pas traiter les 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 les collisions avec les bibliothèques du compilateur / système d'exploitation / standard si vous:

  • ne commence jamais 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, mettre votre code dans un espace de noms unique permet également d'éviter les collisions (mais ne protège pas contre les macros malfaisantes)

Quelques exemples

(J'utilise des macros parce qu'elles sont les plus polluantes des symboles C / C ++, mais cela peut ê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 projet C ++ 0x

A 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 de 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éraux qui ne commencent pas par un trait de soulignement sont réservés pour une normalisation future.

Cette dernière clause prête à confusion, 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 ...


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

Les préfixes d'underscore sont communs dans le code C - un seul trait de soulignement signifie "private", et les doubles caractères de soulignement sont généralement réservés à l'usage du compilateur.





c++-faq