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

Il est courant en C ++ de nommer des variables membres avec une sorte de préfixe pour indiquer qu’elles sont des variables membres, plutôt que des variables ou des parameters locaux. Si vous venez d’un arrière-plan MFC, vous utiliserez probablement m_foo . J’ai aussi vu myFoo occasionnellement.

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

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

  • Réservé dans n’importe quelle scope, 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 soulignement”)
  • Réservé dans l’espace de noms global:
    • identificateurs commençant par un trait de soulignement
  • De plus, tout dans l’espace de noms std est réservé. (Vous êtes autorisé à append des spécialisations de modèles, cependant.)

A partir du standard C ++ 2003:

17.4.3.1.2 Noms globaux [lib.global.names]

Certains jeux 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 namespace ::std (17.4.3.1).

Comme 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), elles s’appliquent également à la norme C 1999:

7.1.3 Identificateurs réservés

Chaque en-tête déclare ou définit tous les identifiants listés dans son sous-paragraphe associé et déclare ou définit facultativement les identifiants listés dans les sous-paragraphes et identifiants associés des futures bibliothèques qui sont toujours réservés pour tout usage ou comme identificateur de scope de fichier.

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

Aucun autre identifiant n’est réservé. Si le programme déclare ou définit un identificateur dans un contexte dans lequel il est réservé (autre que ce qui est autorisé par 7.1.4), ou définit un identificateur réservé en tant que nom de macro, le comportement est indéfini.

Si le programme supprime (avec #undef ) une définition de macro d’un identifiant 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 , setjmp et va_end .

D’autres ressortingctions 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 E suivaient un chiffre ou une lettre majuscule:
    • peut être utilisé pour des noms de code d’erreur supplémentaires.
  • Les noms qui commencent par soit is ou to suivi d’une lettre minuscule
    • peut être utilisé pour des fonctions de test de caractères et de conversion supplémentaires.
  • Noms commençant par LC_ suivi d’une lettre majuscule
    • peut être utilisé pour des macros supplémentaires spécifiant des atsortingbuts de parameters régionaux.
  • Les noms de toutes les fonctions mathématiques existantes suffixées par f ou l sont réservés
    • pour les fonctions correspondantes qui opèrent respectivement sur les arguments float et long double.
  • Les noms commençant par SIG suivis 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 suivis d’une lettre minuscule sont réservés
    • pour les fonctions de chaîne et de tableau supplémentaires.
  • Les noms commençant par PRI ou SCN suivis de toute lettre minuscule ou X sont réservés
    • pour les macros de spécification de format supplémentaires
  • Les noms se _t par _t sont réservés
    • pour les noms de types supplémentaires.

Bien que l’utilisation de ces noms à des fins personnelles puisse ne pas poser de problème, ils peuvent entraîner des conflits avec les futures versions de cette norme.


Personnellement, je ne commence pas les identifiants par des traits de soulignement. Nouvel ajout à ma règle: n’utilisez pas de double soulignement, ce qui est simple car j’utilise rarement le trait de soulignement.

Après avoir effectué 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 un standard POSIX (pas encore sûr) à la recherche de clarification et de chapitre et de vers officiel. Ceci provient 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 être trouvés ici». Les symboles réservés POSIX 2008 sont définis ici. Les ressortingctions sont un peu plus nuancées que celles ci-dessus.

Les règles pour éviter les collisions de noms sont à la fois dans le standard C ++ (voir le livre Stroustrup) et mentionnées par les gourous 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 un cas personnel simple et correct:

Lorsque vous nommez un symbole, vous éviterez les collisions avec les bibliothèques du compilateur / du système d’exploitation / standard si vous:

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

Bien sûr, mettre votre code dans un espace de noms unique aide à éviter les collisions (mais ne protège 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 ça 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 brouillon C ++ 0x

À partir du fichier n3242.pdf (le texte standard final devrait être similaire):

17.6.3.3.2 Noms globaux [global.names]

Certains jeux 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 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 à la normalisation future.

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 …

De MSDN :

L’utilisation de deux caractères de soulignement séquentiels (__) au début d’un identifiant, ou d’un trait de soulignement principal suivi d’une majuscule, est réservé aux implémentations C ++ dans tous les domaines. Vous devez éviter d’utiliser un trait de soulignement principal suivi d’une lettre minuscule pour les noms avec une scope de fichier en raison des conflits possibles avec les identificateurs réservés actuels ou futurs.

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

Ceci semble provenir 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 .

En ce qui concerne 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 un élément interne.

Je le fais même à l’intérieur des classes et des espaces de noms car je n’ai à mémoriser qu’une seule règle (comparée à «à la fin du nom dans le contexte global et au début du nom partout ailleurs»).

Oui, les traits de soulignement peuvent être utilisés n’importe où dans un identifiant. Je crois que les règles sont: n’importe lequel des az, AZ, _ dans le premier caractère et ceux + 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 doublons sont généralement réservés au compilateur.