Quali sono le regole sull'uso di un trattino basso in un identificatore C ++?


931

È comune in C ++ nominare le variabili membro con un qualche tipo di prefisso per indicare il fatto che sono variabili membro, piuttosto che variabili o parametri locali. Se provieni da uno sfondo MFC, probabilmente lo utilizzerai m_foo. L'ho visto anche di myFootanto in tanto.

C # (o forse solo .NET) sembra raccomandare di usare solo un trattino basso, come in _foo. È consentito dallo standard C ++?


3
La pagina di manuale di glibc al riguardo è disponibile su gnu.org/software/libc/manual/html_node/Reserved-Names.html Modifica: vedi anche opengroup.org/onlinepubs/009695399/functions/xsh_chap02_02.html
CesarB

6
Solo per notare che l'ignoranza di queste regole non implica necessariamente che il tuo codice non verrà compilato o eseguito, ma è probabile che il tuo codice non sia portabile su compilatori e versioni diverse, poiché non è possibile garantire che non ci sarà un nome scontri. A sostegno di questo, conosco una certa implementazione di un importante sistema che ha utilizzato come convenzione di denominazione la _ maiuscola ovunque. Lì dove nessun errore dovuto a questo. Certo è una cattiva pratica.
g24l,

Risposte:


852

Le regole (che non sono cambiate in C ++ 11):

  • Riservato in qualsiasi ambito, incluso l'uso come implementazione macro di :
    • identificatori che iniziano con un trattino basso seguito immediatamente da una lettera maiuscola
    • identificatori contenenti caratteri di sottolineatura adiacenti (o "doppio trattino basso")
  • Riservato nello spazio dei nomi globale:
    • identificatori che iniziano con un trattino basso
  • Inoltre, tutto nello stdspazio dei nomi è riservato. (Tuttavia, puoi aggiungere le specializzazioni dei modelli.)

Dallo standard C ++ del 2003:

17.4.3.1.2 Nomi globali [lib.global.names]

Alcuni insiemi di nomi e firme di funzioni sono sempre riservati all'implementazione:

  • Ogni nome che contiene un carattere di sottolineatura doppio ( __) o inizia con un carattere di sottolineatura seguito da una lettera maiuscola (2.11) è riservato all'implementazione per qualsiasi uso.
  • Ogni nome che inizia con un carattere di sottolineatura è riservato all'implementazione per l'uso come nome nello spazio dei nomi globale. 165

165) Tali nomi sono anche riservati nello spazio dei nomi ::std(17.4.3.1).

Poiché il C ++ si basa sullo standard C (1.1 / 2, C ++ 03) e C99 è un riferimento normativo (1.2 / 1, C ++ 03), questi si applicano anche dallo standard C del 1999:

7.1.3 Identificatori riservati

Ogni intestazione dichiara o definisce tutti gli identificatori elencati nella sua sotto-clausola associata e, facoltativamente, dichiara o definisce gli identificatori elencati nella sua sottoclausola e identificatori di direzioni della biblioteca associati associati che sono sempre riservati per qualsiasi uso o per l'uso come identificatori di ambito di file.

  • Tutti gli identificatori che iniziano con un carattere di sottolineatura e una lettera maiuscola o un altro carattere di sottolineatura sono sempre riservati per qualsiasi uso.
  • Tutti gli identificatori che iniziano con un carattere di sottolineatura sono sempre riservati per l'uso come identificatori con ambito di file negli spazi dei nomi ordinari e dei tag.
  • Ciascun nome di macro in uno dei seguenti sottoclausi (comprese le future istruzioni della libreria) è riservato per l'uso come specificato se è inclusa una delle intestazioni associate; se non diversamente specificato (vedere 7.1.4).
  • Tutti gli identificatori con collegamento esterno in uno dei seguenti sottoclausi (comprese le future direzioni della biblioteca) sono sempre riservati per l'uso come identificatori con collegamento esterno. 154
  • Ogni identificatore con ambito di file elencato in uno dei seguenti sottoclausi (comprese le direzioni future della libreria) è riservato per l'uso come nome di macro e come identificatore con ambito di file nello stesso spazio dei nomi se è inclusa una delle intestazioni associate.

Nessun altro identificatore è riservato. Se il programma dichiara o definisce un identificatore in un contesto in cui è riservato (diverso da quello consentito dalla 7.1.4) o definisce un identificatore riservato come nome di macro, il comportamento non è definito.

Se il programma rimuove (con #undef) qualsiasi definizione macro di un identificatore nel primo gruppo sopra elencato, il comportamento non è definito.

154) L'elenco degli identificatori riservati con collegamento esterno comprende errno, math_errhandling, setjmp, e va_end.

Potrebbero essere applicate altre restrizioni. Ad esempio, lo standard POSIX riserva molti identificatori che potrebbero essere visualizzati nel codice normale:

  • I nomi che iniziano con la maiuscola hanno Eseguito una cifra o una lettera maiuscola:
    • può essere utilizzato per nomi di codici di errore aggiuntivi.
  • Nomi che iniziano con isoto seguiti da una lettera minuscola
    • può essere utilizzato per ulteriori funzioni di test e conversione dei caratteri.
  • Nomi che iniziano con LC_seguito da una lettera maiuscola
    • può essere utilizzato per macro aggiuntive che specificano gli attributi della locale.
  • I nomi di tutte le funzioni matematiche esistenti sono stati aggiunti fo lriservati
    • per le funzioni corrispondenti che operano rispettivamente su float e long double argomenti.
  • I nomi che iniziano con SIGseguito da una lettera maiuscola sono riservati
    • per nomi di segnali aggiuntivi.
  • I nomi che iniziano con SIG_seguito da una lettera maiuscola sono riservati
    • per ulteriori azioni di segnale.
  • I nomi che iniziano con str, memo wcsseguiti da una lettera minuscola sono riservati
    • per funzioni aggiuntive di stringa e matrice.
  • Nomi che iniziano con PRIo SCNseguiti da una lettera minuscola oX sono riservati
    • per ulteriori macro identificatore di formato
  • I nomi che terminano con _tsono riservati
    • per nomi di tipi aggiuntivi.

Mentre usare questi nomi per i tuoi scopi in questo momento potrebbe non causare problemi, aumentano la possibilità di conflitto con le versioni future di quello standard.


Personalmente, non avvio identificatori con caratteri di sottolineatura. Nuova aggiunta alla mia regola: non usare i caratteri di sottolineatura doppi da nessuna parte, il che è facile poiché uso raramente il trattino basso.

Dopo aver fatto delle ricerche su questo articolo, non finisco più con i miei identificatori _t poiché questo è riservato dallo standard POSIX.

La regola su qualsiasi identificatore che termina con _tmi ha sorpreso molto. Penso che sia uno standard POSIX (non ancora sicuro) in cerca di chiarimenti e capitolo e verso ufficiali. Questo è dal manuale GNU libtool , che elenca i nomi riservati.

CesarB ha fornito il seguente link ai simboli riservati di POSIX 2004 e osserva "che molti altri prefissi e suffissi riservati ... possono essere trovati lì". I simboli riservati di POSIX 2008 sono definiti qui. Le restrizioni sono leggermente più sfumate rispetto a quelle sopra.


14
Lo standard C ++ non "importa" quello C, vero? Importano determinate intestazioni, ma non la lingua nel suo insieme, o regole di denominazione, per quanto ne so. Ma sì, anche quello mi ha sorpreso. Ma dal momento che è C, può applicarsi solo al ns globale. Dovrei essere sicuro di usare _t all'interno delle lezioni mentre lo leggo
jalf

27
Lo standard C ++ non "importa" lo standard C. Fa riferimento allo standard C. L'introduzione alla libreria C ++ dice "La libreria rende disponibili anche le strutture della libreria C standard". Lo fa includendo le intestazioni della libreria C Standard con le modifiche appropriate, ma non "importandolo". Lo standard C ++ ha un proprio set di regole che descrive i nomi riservati. Se un nome riservato in C deve essere riservato in C ++, quello è il posto dove dirlo. Ma lo standard C ++ non lo dice. Quindi non credo che le cose riservate in C siano riservate in C ++ - ma potrei anche sbagliarmi.
Johannes Schaub - litb,

8
Questo è ciò che ho scoperto sul problema "_t": n1256 (C99 TC3) dice: "I nomi dei typedef che iniziano con int o uint e terminano con _t" sono riservati. Penso che permetta ancora di usare nomi come "foo_t" - ma penso che questi siano quindi riservati da POSIX.
Johannes Schaub - litb,

59
Quindi 'tolleranza' è riservata da POSIX in quanto inizia con 'a' + una lettera minuscola? Scommetto che un sacco di codice infrange questa regola!
Sjoerd,

23
@LokiAstari, " Lo standard C ++ è definito in termini di standard C. Fondamentalmente dice che il C ++ è C con queste differenze e aggiunte. " Sciocchezze! C ++ fa riferimento solo allo standard C in [basic.fundamental] e alla libreria. Se ciò che dici è vero, dove lo dice C ++ _Boole _Imaginarynon esiste in C ++? Il linguaggio C ++ è definito esplicitamente, non in termini di "modifiche" a C, altrimenti lo standard potrebbe essere molto più breve!
Jonathan Wakely,

198

Le regole per evitare la collisione dei nomi sono entrambe nello standard C ++ (vedi il libro di Stroustrup) e menzionate dai guru C ++ (Sutter, ecc.).

Regola personale

Poiché non volevo occuparmi dei casi e volevo una semplice regola, ho progettato un personale che sia semplice e corretta:

Quando si assegna un nome a un simbolo, si eviterà la collisione con le librerie compilatore / OS / standard se:

  • non avviare mai un simbolo con un carattere di sottolineatura
  • non nominare mai un simbolo con due caratteri di sottolineatura consecutivi all'interno.

Naturalmente, inserire il codice in uno spazio dei nomi univoco aiuta anche a evitare le collisioni (ma non proteggerà dalle macro malvagie)

Qualche esempio

(Uso le macro perché sono il codice più inquinante dei simboli C / C ++, ma potrebbe essere qualsiasi cosa, dal nome della variabile al nome della classe)

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

Estratti dalla bozza C ++ 0x

Dal file n3242.pdf (mi aspetto che il testo standard finale sia simile):

17.6.3.3.2 Nomi globali [global.names]

Alcuni insiemi di nomi e firme di funzioni sono sempre riservati all'implementazione:

- Ogni nome che contiene un doppio carattere di sottolineatura _ _ o inizia con un carattere di sottolineatura seguito da una lettera maiuscola (2.12) è riservato all'implementazione per qualsiasi uso.

- Ogni nome che inizia con un carattere di sottolineatura è riservato all'implementazione per l'uso come nome nello spazio dei nomi globale.

Ma anche:

17.6.3.3.5 Suffissi letterali definiti dall'utente [usrlit.suffix]

Gli identificatori di suffisso letterali che non iniziano con un carattere di sottolineatura sono riservati per la futura standardizzazione.

Quest'ultima clausola è confusa, a meno che non si consideri che un nome che inizia con un carattere di sottolineatura e seguito da una lettera minuscola sarebbe OK se non definito nello spazio dei nomi globale ...


9
@Meysam: __WRONG_AGAIN__contiene due trattini bassi consecutivi (due all'inizio e due alla fine), quindi questo è sbagliato secondo lo standard.
Paercebal,

8
@ BЈовић: WRONG__WRONGcontiene due trattini bassi consecutivi (due nel mezzo), quindi questo è sbagliato secondo lo standard
paercebal

2
inserire il codice in uno spazio dei nomi univoco aiuta anche a evitare le collisioni : ma questo non è ancora sufficiente, poiché l'identificatore può scontrarsi con una parola chiave indipendentemente dall'ambito (ad esempio __attribute__per GCC).
Ruslan,

1
Perché c'è qualche problema ad avere due underscore consecutivi nel mezzo secondo lo standard? I suffissi letterali definiti dall'utente si applicano a valori letterali come 1234567Lo 4.0f; IIRC si riferisce a ohttp: //it.cppreference.com/w/cpp/language/user_literal
Jason S

2
Why is there any problem of having two consecutive underscores in the middle according to the standard?Perché lo standard dice che quelli sono riservati. Questo non è un consiglio sullo stile buono o cattivo. È una decisione dallo standard. Perché hanno deciso questo? Immagino che i primi compilatori abbiano già usato tali convenzioni in modo informale prima della standardizzazione.
Paercebal,

38

Da MSDN :

L'uso di due caratteri di sottolineatura sequenziali (__) all'inizio di un identificatore, o di un singolo carattere di sottolineatura iniziale seguito da una lettera maiuscola, è riservato per le implementazioni C ++ in tutti gli ambiti. Dovresti evitare di usare un carattere di sottolineatura iniziale seguito da una lettera minuscola per i nomi con ambito di file a causa di possibili conflitti con identificatori riservati attuali o futuri.

Ciò significa che è possibile utilizzare un singolo trattino basso come prefisso della variabile membro, purché sia ​​seguito da una lettera minuscola.

Questo è apparentemente preso dalla sezione 17.4.3.1.2 dello standard C ++, ma non riesco a trovare una fonte originale per lo standard completo online.

Vedi anche questa domanda .


2
Ho trovato un testo simile in n3092.pdf (la bozza dello standard C ++ 0x) alla sezione: "17.6.3.3.2 Nomi globali"
paercebal,

7
È interessante notare che questa sembra essere l'unica risposta che ha una risposta diretta e concisa alla domanda.
hyde,

9
@hyde: In realtà non lo è, dal momento che sta saltando la regola per non avere identificatori con un carattere di sottolineatura iniziale nello spazio dei nomi globale. Vedi la risposta di Roger . Diffiderei molto delle citazioni dei documenti MS VC come autorità sullo standard C ++.
sabato

@sbi Mi riferivo a "puoi usare un singolo trattino basso come prefisso di una variabile membro, purché sia ​​seguito da una lettera minuscola" in questa risposta, che risponde alla domanda sul testo della domanda direttamente e in modo conciso, senza essere annegato in un muro di testo.
hyde,

5
In primo luogo, considero ancora la mancanza di alcun suggerimento secondo cui la stessa regola non si applica allo spazio dei nomi globale come un fallimento. Quel che è peggio, tuttavia, è che i caratteri di sottolineatura adiacenti sono vietati non solo all'inizio, ma ovunque all'interno di un identificatore. Quindi questa risposta non sta semplicemente omettendo un fatto, ma in realtà fa almeno una richiesta attivamente sbagliata. Come ho detto, fare riferimento ai documenti MSVC è qualcosa che non farei a meno che la domanda non riguardi esclusivamente VC.
sabato

25

Per quanto riguarda l'altra parte della domanda, è comune mettere il carattere di sottolineatura alla fine del nome della variabile per non scontrarsi con qualcosa di interno.

Lo faccio anche all'interno di classi e spazi dei nomi perché devo solo ricordare una regola (rispetto a "alla fine del nome in ambito globale e all'inizio del nome ovunque").


2

Sì, i caratteri di sottolineatura possono essere utilizzati ovunque in un identificatore. Credo che le regole siano: una qualsiasi di az, AZ, _ nel primo carattere e quelle + 0-9 per i seguenti caratteri.

I prefissi dei caratteri di sottolineatura sono comuni nel codice C: un singolo carattere di sottolineatura significa "privato" e i caratteri di sottolineatura doppi sono di solito riservati al compilatore.


3
Sono comuni nelle biblioteche. Non dovrebbero essere comuni nel codice utente.
Martin York,

43
Le persone fanno le librerie di scrittura in C, si sa.
John Millikin,

7
"Sì, i trattini bassi possono essere usati ovunque in un identificatore." Questo è sbagliato per gli identificatori globali. Vedi la risposta di Roger .
sabato
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.