web-dev-qa-db-fra.com

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

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

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

891
Roger Lipscombe

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

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

À partir 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 à la mise en oeuvre:

  • Chaque nom qui contient un double trait de soulignement (__) ou commence par un trait de soulignement suivi d'une lettre majuscule (2.11) est réservé à la mise en oeuvre pour toute utilisation.
  • Chaque nom commençant par un trait de soulignement est réservé à l'implémentation pour pouvoir ê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).

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

7.1.3 Identifiants réservés

Chaque en-tête déclare ou définit tous les identificateurs répertoriés dans sa sous-clause associée et éventuellement identifie ou définit les identificateurs répertoriés dans sa sous-clause d'instructions de bibliothèque future associée et les identificateurs qui sont toujours réservés pour toute utilisation ou pour être utilisés comme identificateurs de portée 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 pour toute utilisation.
  • Tous les identificateurs commençant par un trait de soulignement sont toujours réservés à une utilisation en tant qu'identificateurs avec une étendue de fichier dans les espaces de nom de balise et ordinaire.
  • Chaque nom de macro dans l’un des sous-paragraphes suivants (y compris les instructions futures de la bibliothèque) est réservé pour une utilisation spécifiée si l’un des en-têtes associés est inclus; sauf indication explicite contraire (voir 7.1.4).
  • Tous les identifiants avec une liaison externe dans l’un des sous-paragraphes suivants (y compris les instructions futures de la bibliothèque) sont toujours réservés à une utilisation en tant qu’identifiants avec une liaison externe.154
  • Chaque identifiant avec une étendue de fichier répertoriée dans l’un des sous-paragraphes suivants (y compris les instructions futures de la bibliothèque) est réservé à l’utilisation en tant que nom de macro et en tant qu’identifiant avec une étendue de fichier dans le même espace de nom 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 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é en tant que nom de macro, le comportement est indéfini.

Si le programme supprime (avec #undef) toute définition de macro d'un identificateur du 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 restrictions peuvent s'appliquer. Par exemple, la norme POSIX réserve de nombreux identifiants susceptibles d'apparaître dans le code normal:

  • Les noms commençant par une majuscule E suivaient un chiffre ou une lettre majuscule:
    • peut être utilisé pour d'autres noms de code d'erreur.
  • Noms commençant par is ou to suivi d'une lettre minuscule
    • peut être utilisé pour des tests de caractères supplémentaires et des fonctions de conversion.
  • 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 suffixées de 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 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, 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 de toute lettre minuscule ou X sont réservés
    • pour des macros de spécificateur de format supplémentaires
  • Les noms qui se terminent par _t sont réservés
    • pour des noms de type supplémentaires.

L'utilisation de ces noms pour vos propres besoins actuels ne pose aucun problème, mais il existe un risque de conflit avec les versions futures de cette norme.


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

Après avoir effectué des recherches sur cet article, je ne termine plus mes identifiants avec _t car celui-ci 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) qui cherche une clarification, un chapitre et un vers officiels. Ceci est tiré du manuel de la librairie GN , listant les noms réservés.

CesarB a fourni le lien suivant vers les symboles et notes réservés POSIX 2004 "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.

809
Martin York

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

En nommant un symbole, vous éviterez les conflits avec les bibliothèques du 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 conflits (sans vous protéger contre les macros diaboliques).

Quelques exemples

(J'utilise des macros car ce sont les symboles C/C++ qui polluent le plus en code, mais cela peut aller de nom de variable à nom de classe)

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

Extraits du brouillon C++ 0x

A partir du fichier n3242.pdf (j'attends que le texte standard final soit similaire):

17.6.3.3.2 Noms globaux [noms.globaux]

Certains ensembles de noms et de signatures de fonctions sont toujours réservés à la mise en oeuvre:

- Chaque nom contenant un double trait de soulignement _ _ ou commençant par un trait de soulignement suivi d'une lettre majuscule (2.12) est réservé à la mise en oeuvre pour toute utilisation.

- Chaque nom commençant par un trait de soulignement est réservé à l'implémentation pour pouvoir ê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 la normalisation future.

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

189
paercebal

De MSDN :

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

Cela signifie que vous pouvez utiliser un simple 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 de la norme C++, mais je ne trouve pas de source originale pour la norme complète en ligne.

Voir aussi cette question .

35
Roger Lipscombe

Pour ce qui est de l’autre partie de la question, il est courant de mettre le trait de soulignement à la fin du nom de la variable afin de ne pas entrer en conflit avec quelque chose d’interne.

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

23
Max Lybbert

Oui, les traits de soulignement peuvent être utilisés n'importe où dans un identifiant. Je crois que les règles sont les suivantes: a-z, A-Z, _ 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 soulignement simple signifie "privé", et les soulignements doubles sont généralement réservés au compilateur.

3
John Millikin