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

Oct 23 2008

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

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

Respostas

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

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

  • Reservado em qualquer escopo, incluindo 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 que começam com um sublinhado
  • Além disso, tudo no stdnamespace é reservado. (Você tem permissão para adicionar especializações de modelo, no entanto.)

Do padrão C ++ de 2003:

17.4.3.1.2 Nomes globais [lib.global.names]

Certos conjuntos de nomes e assinaturas de função 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 para a implementação para uso como um nome no namespace global. 165

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

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

7.1.3 Identificadores reservados

Cada cabeçalho declara ou define todos os identificadores listados em sua subseção associada e, opcionalmente, declara ou define os identificadores listados em sua subseção de direções da biblioteca futura associada 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 de nomes comuns e de tag.
  • Cada nome de macro em qualquer uma das subseções a seguir (incluindo as futuras instruções da biblioteca) é reservado para uso conforme especificado se qualquer um de seus cabeçalhos associados for incluído; a menos que seja explicitamente declarado de outra forma (ver 7.1.4).
  • Todos os identificadores com ligação externa em qualquer uma das seguintes subcláusulas (incluindo as futuras instruções da biblioteca) são sempre reservados para uso como identificadores com ligação externa. 154
  • Cada identificador com escopo de arquivo listado em qualquer uma das subcláusulas a seguir (incluindo as futuras instruçõ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 cabeçalhos associados for incluído.

Nenhum outro identificador é reservado. Se o programa declara ou define um identificador em um contexto no qual está 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 ligação 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 que começam com maiúscula Eseguidos de um dígito ou letra maiúscula:
    • pode ser usado para nomes de código de erro adicionais.
  • Nomes que começam com isou toseguidos por uma letra minúscula
    • pode ser usado para testes de caracteres adicionais e funções de conversão.
  • Nomes que começam com LC_seguido por uma letra maiúscula
    • pode ser usado para macros adicionais que especificam atributos de localidade.
  • Nomes de todas as funções matemáticas existentes com sufixo fou lsão reservados
    • para funções correspondentes que operam em argumentos float e long double, respectivamente.
  • Os nomes que começam com SIGseguido por uma letra maiúscula são reservados
    • para nomes de sinais adicionais.
  • Os nomes que começam com SIG_seguido por uma letra maiúscula são reservados
    • para ações de sinal adicionais.
  • Nomes que começam com str, memou wcsseguidos por uma letra minúscula são reservados
    • para funções adicionais de string e array.
  • Nomes que começam com PRIou SCNseguidos por qualquer letra minúscula ou Xsão reservados
    • para macros de especificador de formato adicionais
  • Nomes que terminam com _tsão reservados
    • para nomes de tipo adicionais.

Embora usar esses nomes para seus próprios fins agora possa não causar problemas, eles levantam a possibilidade de conflito com versões futuras desse padrão.


Pessoalmente, simplesmente não começo identificadores com sublinhados. Novo acréscimo à minha regra: não use sublinhados duplos em qualquer lugar, o que é fácil, pois raramente uso sublinhados.

Depois de pesquisar este artigo, não termino mais meus identificadores com, _tpois isso é reservado pelo padrão POSIX.

A regra sobre qualquer identificador que termina com _tme surpreendeu muito. Eu acho que é um padrão POSIX (não tenho certeza ainda) procurando esclarecimento e capítulo e versículo 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.

202 paercebal Oct 23 2008 at 14:27

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

Regra pessoal

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

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

  • nunca comece um símbolo com um sublinhado
  • nunca nomeie um símbolo com dois sublinhados consecutivos dentro.

Claro, colocar seu código em um namespace exclusivo também ajuda a evitar colisões (mas não protege contra macros malignas)

Alguns exemplos

(Eu uso macros porque são os mais poluentes de código dos símbolos C / C ++, mas pode ser qualquer coisa, desde o nome da variável até o nome da classe)

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

Extrai do rascunho 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 função 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]

Os identificadores de sufixo literais que não começam com um sublinhado são reservados para padronização futura.

Esta última cláusula é confusa, a menos que você considere que um nome começando com um sublinhado e seguido por uma letra minúscula estaria OK se não fosse definido no namespace global ...

40 RogerLipscombe Oct 23 2008 at 14:06

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 C ++ em todos os escopos. Você deve evitar usar um sublinhado inicial seguido por uma letra minúscula para nomes com escopo de arquivo por causa de possíveis conflitos com identificadores reservados atuais ou futuros.

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

Aparentemente, isso foi tirado da seção 17.4.3.1.2 do padrão C ++, mas não consigo encontrar uma fonte original para o padrão completo online.

Veja também esta questão .

25 MaxLybbert Nov 15 2008 at 03:03

Quanto à outra parte da pergunta, é 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 classes e namespaces, porque então só preciso me lembrar de uma regra (em comparação com "no final do nome no escopo global e o início do nome em todos os outros lugares").

1 JohnMillikin Oct 23 2008 at 14:05

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

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