Quais são as regras sobre o uso de um sublinhado em um identificador de C ++?

É comum em C ++ nomear variables ​​de membro com algum tipo de prefixo para denotar o fato de que são variables ​​de membro, em vez de variables ​​ou parâmetros locais. Se você veio de um fundo MFC, você provavelmente usará m_foo . Eu também vi myFoo ocasionalmente.

C # (ou possivelmente apenas .NET) parece recomendar usar apenas um sublinhado, como em _foo . Isso é permitido pelo padrão C ++?

As regras (que não foram alteradas no C ++ 11):

  • Reservado em qualquer escopo, inclusive para uso como macros de implementação:
    • identificadores que começam com um sublinhado seguido imediatamente por uma letra maiúscula
    • identificadores contendo sublinhados adjacentes (ou “sublinhado duplo”)
  • Reservado no namespace global:
    • identificadores começando com um sublinhado
  • Além disso, tudo no namespace std é reservado. (Você tem permissão para adicionar especializações de modelo, no entanto.)

Do padrão 2003 C ++:

17.4.3.1.2 Nomes globais [lib.global.names]

Certos conjuntos de nomes e assinaturas de function são sempre reservados para a implementação:

  • Cada nome que contém um sublinhado duplo ( __ ) ou começa com um sublinhado seguido por uma letra maiúscula (2.11) é reservado para a implementação para qualquer uso.
  • Cada nome que começa com um sublinhado é reservado à implementação para uso como um nome no namespace global. 165

165) Tais nomes também são reservados em namespace ::std (17.4.3.1).

Como o C ++ é baseado no padrão C (1.1 / 2, C ++ 03) e C99 é uma referência normativa (1.2 / 1, C ++ 03), estes também se aplicam, a partir do Padrão C de 1999:

7.1.3 Identificadores reservados

Cada header declara ou define todos os identificadores listados em sua subcláusula associada e, opcionalmente, declara ou define identificadores listados em sua subcláusula de direções de bibliotecas futuras associadas e identificadores que são sempre reservados para qualquer uso ou para uso como identificadores de escopo de arquivo.

  • Todos os identificadores que começam com um sublinhado e uma letra maiúscula ou outro sublinhado são sempre reservados para qualquer uso.
  • Todos os identificadores que começam com um sublinhado são sempre reservados para uso como identificadores com escopo de arquivo nos espaços comuns e de nome de tag.
  • Cada nome de macro em qualquer uma das sub-cláusulas a seguir (incluindo as futuras direções da biblioteca) é reservado para uso conforme especificado, se qualquer um de seus headers associados for incluído; salvo indicação explícita em contrário (ver 7.1.4).
  • Todos os identificadores com binding externa em qualquer uma das seguintes sub-cláusulas (incluindo as futuras direções da biblioteca) são sempre reservados para uso como identificadores com binding externa. 154
  • Cada identificador com escopo de arquivo listado em qualquer uma das sub-cláusulas a seguir (incluindo as futuras direções da biblioteca) é reservado para uso como um nome de macro e como um identificador com escopo de arquivo no mesmo espaço de nome se qualquer um de seus headers associados for incluído.

Nenhum outro identificador é reservado. Se o programa declara ou define um identificador em um contexto no qual ele é reservado (diferente do permitido por 7.1.4), ou define um identificador reservado como um nome de macro, o comportamento é indefinido.

Se o programa remover (com # #undef ) qualquer definição de macro de um identificador no primeiro grupo listado acima, o comportamento é indefinido.

154) A lista de identificadores reservados com binding externa inclui errno , math_errhandling , setjmp e va_end .

Outras restrições podem ser aplicadas. Por exemplo, o padrão POSIX reserva muitos identificadores que provavelmente aparecerão no código normal:

  • Nomes começando com um maiúscula E seguiram um dígito ou uma letra maiúscula:
    • pode ser usado para nomes de código de erro adicionais.
  • Os nomes que começam com ou is seguidos por uma letra minúscula
    • pode ser usado para testes adicionais de caracteres e funções de conversão.
  • Nomes que começam com LC_ seguidos por uma letra maiúscula
    • pode ser usado para macros adicionais especificando atributos de localidade.
  • Os nomes de todas as funções matemáticas existentes com sufixo f ou l são reservados
    • para funções correspondentes que operam em argumentos float e double double, respectivamente.
  • Nomes que começam com SIG seguidos por uma letra maiúscula são reservados
    • para nomes de sinal adicionais.
  • Nomes que começam com SIG_ seguidos por uma letra maiúscula são reservados
    • para ações de sinal adicionais.
  • Nomes começando com str , mem ou wcs seguidos por uma letra minúscula são reservados
    • para funções adicionais de string e array.
  • Nomes começando com PRI ou SCN seguidos por qualquer letra minúscula ou X são reservados
    • para macros especificador de formato adicionais
  • Nomes que terminam com _t são reservados
    • para nomes de tipo adicionais.

Embora o uso desses nomes para seus próprios propósitos no momento não cause problemas, eles criam a possibilidade de conflito com futuras versões desse padrão.


Pessoalmente, apenas não inicio identificadores com sublinhados. Nova adição à minha regra: não use sublinhados duplos em nenhum lugar, o que é fácil, pois raramente uso sublinhado.

Depois de fazer pesquisas sobre este artigo, não termino mais meus identificadores com _t pois isso é reservado pelo padrão POSIX.

A regra sobre qualquer identificador que termine com _t me surpreendeu muito. Eu acho que é um padrão POSIX (ainda não tenho certeza) em busca de esclarecimentos e capítulos e versos oficiais. Isto é do manual GNU libtool , listando nomes reservados.

CesarB forneceu o seguinte link para os símbolos reservados POSIX 2004 e notas “que muitos outros prefixos e sufixos reservados … podem ser encontrados lá”. Os símbolos reservados do POSIX 2008 são definidos aqui. As restrições são um pouco mais sutis do que as acima.

As regras para evitar a colisão de nomes estão no padrão C ++ (veja o livro Stroustrup) e mencionadas por gurus C ++ (Sutter, etc.).

Regra pessoal

Como não queria lidar com casos e queria uma regra simples, criei uma regra pessoal simples e correta:

Ao nomear um símbolo, você evitará colisões com compilador / sistema operacional / bibliotecas padrão se:

  • Nunca inicie um símbolo com um sublinhado
  • nunca nomeie um símbolo com dois sublinhados consecutivos no interior.

É claro que colocar seu código em um namespace exclusivo também ajuda a evitar a colisão (mas não protege contra macros malignas)

Alguns exemplos

(Eu uso macros porque elas são mais poluidoras de códigos de símbolos C / C ++, mas podem ser qualquer coisa, desde o nome da variável até o nome da class)

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

Extrações do rascunho do C ++ 0x

Do arquivo n3242.pdf (espero que o texto padrão final seja semelhante):

17.6.3.3.2 Nomes globais [global.names]

Certos conjuntos de nomes e assinaturas de function são sempre reservados para a implementação:

– Cada nome que contém um sublinhado duplo _ _ ou começa com um sublinhado seguido por uma letra maiúscula (2.12) é reservado para a implementação para qualquer uso.

– Cada nome que começa com um sublinhado é reservado para a implementação para uso como um nome no namespace global.

Mas também:

17.6.3.3.5 Sufixos literais definidos pelo usuário [usrlit.suffix]

Identificadores de sufixo literais que não iniciam com um sublinhado são reservados para padronização futura.

Esta última cláusula é confusa, a menos que você considere que um nome que comece com um sublinhado e seja seguido por uma letra minúscula seja OK se não estiver definido no namespace global …

Do MSDN :

O uso de dois caracteres de sublinhado sequenciais (__) no início de um identificador, ou um único sublinhado inicial seguido por uma letra maiúscula, é reservado para implementações de C ++ em todos os escopos. Você deve evitar usar um sublinhado inicial seguido por uma letra minúscula para nomes com escopo de arquivo devido a possíveis conflitos com identificadores reservados atuais ou futuros.

Isso significa que você pode usar um único sublinhado como um prefixo de variável de membro, desde que seja seguido por uma letra minúscula.

Isto é aparentemente retirado da seção 17.4.3.1.2 do padrão C ++, mas não consigo encontrar uma fonte original para o padrão online completo.

Veja também esta questão .

Quanto à outra parte da questão, é comum colocar o sublinhado no final do nome da variável para não colidir com nada interno.

Eu faço isso mesmo dentro de classs e namespaces, porque eu só tenho que lembrar de uma regra (em comparação com “no final do nome no escopo global e o início do nome em qualquer outro lugar”).

Sim, os sublinhados podem ser usados ​​em qualquer lugar em um identificador. Eu acredito que as regras são: qualquer um dos az, AZ, _ no primeiro caractere e aqueles + 0-9 para os seguintes caracteres.

Os prefixos de sublinhado são comuns no código C – um único sublinhado significa “privado” e sublinhados duplos são geralmente reservados para uso pelo compilador.