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

Oct 23 2008

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

C # (o forse solo .NET) sembra consigliare di utilizzare solo un carattere di sottolineatura, come in _foo. Questo è consentito dallo standard C ++?

Risposte

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

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

  • Riservato in qualsiasi ambito, incluso per l'uso come macro di implementazione :
    • identificatori che iniziano con un trattino basso seguito immediatamente da una lettera maiuscola
    • identificatori contenenti trattini bassi 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 set di nomi e firme di funzioni sono sempre riservati all'implementazione:

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

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

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

7.1.3 Identificatori riservati

Ciascuna intestazione dichiara o definisce tutti gli identificatori elencati nella sottoclausola associata e opzionalmente dichiara o definisce gli identificatori elencati nella clausola secondaria delle istruzioni della libreria futura associata e gli identificatori che sono sempre riservati per qualsiasi uso o per l'uso come identificatori dell'ambito del file.

  • Tutti gli identificatori che iniziano con un trattino basso e una lettera maiuscola o un altro trattino basso sono sempre riservati per qualsiasi uso.
  • Tutti gli identificatori che iniziano con un trattino basso sono sempre riservati per essere utilizzati come identificatori con ambito di file sia negli spazi dei nomi ordinari che in quelli dei tag.
  • Ogni nome di macro in una qualsiasi delle seguenti sottoclausole (comprese le future istruzioni della libreria) è riservato per l'uso come specificato se viene inclusa una delle sue intestazioni associate; salvo diversa indicazione esplicita (vedere 7.1.4).
  • Tutti gli identificatori con collegamento esterno in una qualsiasi delle seguenti sottoclausole (comprese le future indicazioni della libreria) sono sempre riservati per l'uso come identificatori con collegamento esterno. 154
  • Ogni identificatore con ambito di file elencato in una delle seguenti sottoclausole (comprese le future istruzioni 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 quanto 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 di 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 limitazioni. Ad esempio, lo standard POSIX riserva molti identificatori che potrebbero essere visualizzati nel codice normale:

  • I nomi che iniziano con una maiuscola Eseguiti da una cifra o da una lettera maiuscola:
    • può essere utilizzato per nomi di codici di errore aggiuntivi.
  • Nomi che iniziano con uno iso toseguiti da una lettera minuscola
    • può essere utilizzato per ulteriori test dei caratteri e funzioni di conversione.
  • Nomi che iniziano con LC_seguito da una lettera maiuscola
    • può essere utilizzato per macro aggiuntive che specificano attributi locali.
  • I nomi di tutte le funzioni matematiche esistenti con suffisso fo lsono riservati
    • per le funzioni corrispondenti che operano su float e argomenti double lunghi, rispettivamente.
  • 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 del segnale.
  • I nomi che iniziano con str, memo wcsseguiti da una lettera minuscola sono riservati
    • per funzioni aggiuntive di stringhe e array.
  • I nomi che iniziano con PRIo SCNseguiti da una qualsiasi lettera minuscola o Xsono riservati
    • per ulteriori macro identificatori di formato
  • I nomi che finiscono con _tsono riservati
    • per nomi di tipi aggiuntivi.

Sebbene utilizzare questi nomi per i propri scopi in questo momento potrebbe non causare problemi, sollevano la possibilità di conflitto con le versioni future di quello standard.


Personalmente non inizio gli identificatori con trattini bassi. Nuova aggiunta alla mia regola: non utilizzare doppi trattini bassi da nessuna parte, il che è facile poiché utilizzo raramente il carattere di sottolineatura.

Dopo aver fatto ricerche su questo articolo, non concludo più i miei identificatori _tpoiché 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) alla ricerca di chiarimenti e capitolo e versetto ufficiali. Questo è tratto dal manuale GNU libtool , che elenca i nomi riservati.

CesarB ha fornito il seguente collegamento ai simboli riservati di POSIX 2004 e alle note "che molti altri prefissi e suffissi riservati ... possono essere trovati lì". I simboli riservati POSIX 2008 sono definiti qui. Le restrizioni sono un po 'più sfumate di quelle sopra.

202 paercebal Oct 23 2008 at 14:27

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

Regola personale

Poiché non volevo occuparmi di casi e volevo una regola semplice, ne ho progettata una personale che sia allo stesso tempo semplice e corretta:

Quando si nomina un simbolo, si eviterà la collisione con il compilatore / OS / librerie standard se:

  • non iniziare mai un simbolo con un trattino basso
  • non nominare mai un simbolo con due trattini bassi consecutivi all'interno.

Ovviamente, inserire il codice in uno spazio dei nomi univoco aiuta anche a evitare la collisione (ma non protegge dalle macro malvagie)

Qualche esempio

(Uso le macro perché sono le più inquinanti del codice 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 set di nomi e firme di funzioni sono sempre riservati all'implementazione:

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

- Ogni nome che inizia con un trattino basso è riservato all'implementazione per essere utilizzato 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 letterale che non iniziano con un trattino basso sono riservati per la standardizzazione futura.

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

40 RogerLipscombe Oct 23 2008 at 14:06

Da MSDN :

L'utilizzo di due caratteri di sottolineatura sequenziali (__) all'inizio di un identificatore o di un singolo trattino di sottolineatura iniziale seguito da una lettera maiuscola è riservato alle implementazioni C ++ in tutti gli ambiti. È necessario evitare di utilizzare un trattino basso 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 .

25 MaxLybbert Nov 15 2008 at 03:03

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

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

1 JohnMillikin Oct 23 2008 at 14:05

Sì, i trattini bassi possono essere usati ovunque in un identificatore. Credo che le regole siano: uno qualsiasi di az, AZ, _ nel primo carattere e quelli + 0-9 per i seguenti caratteri.

I prefissi di sottolineatura sono comuni nel codice C: un singolo trattino basso significa "privato", mentre i doppi trattini bassi sono solitamente riservati all'uso da parte del compilatore.