Quais são as convenções de nomenclatura mais comuns em C?

125

Quais são as convenções de nomenclatura comumente usadas em C? Eu sei que existem pelo menos dois:

  1. GNU / linux / K&R com lower_case_functions
  2. ? nome? com funções UpperCaseFoo

Eu estou falando sobre C apenas aqui. A maioria de nossos projetos são pequenos sistemas embarcados nos quais usamos C.

Aqui está o que estou planejando usar para o meu próximo projeto:


Convenção de nomenclatura C

Struct              TitleCase
Struct Members      lower_case or lowerCase

Enum                ETitleCase
Enum Members        ALL_CAPS or lowerCase

Public functions    pfx_TitleCase (pfx = two or three letter module prefix)
Private functions   TitleCase
Trivial variables   i,x,n,f etc...
Local variables     lower_case or lowerCase
Global variables    g_lowerCase or g_lower_case (searchable by g_ prefix)
JeffV
fonte
7
Eu não forçaria um prefixo 'g_' em variáveis ​​globais; Eu aplicaria nomes significativos (então client_locale e não cl_lc como um nome de variável global). O clássico C não usa estojo de camelo; Escrevi código em camel-case em C, e parece estranho (então não faço mais isso assim). Dito isto, não está errado - e a consistência é mais importante do que qual convenção é usada. Evite typedefs que encapsulam ponteiros de estrutura; considere o padrão C - 'FILE *' está escrito assim, não FILE_PTR.
11136 Jonathan Leffler
2
@ Jonathan Leffler, o que há de errado com g_ para significar globais? Em sistemas embarcados, já tive problemas antes, nos quais era difícil rastrear dependências entre módulos através de vars globais e g_somevar externo. Pessoalmente, acho que geralmente é uma má ideia, mas esse tipo de coisa geralmente é feito por razões de desempenho. Por exemplo, um sinalizador global definido por uma interrupção indicando que os dados estão prontos.
11139 JeffV
2
Pelo que vale, essa convenção de nomenclatura foi principalmente extraída das convenções da API do PalmOS. Além disso, é semelhante à convenção usada no livro de O'Reilly: "Programando sistemas embarcados com ferramentas de desenvolvimento C e GNU". Pessoalmente, gosto do TitleCase nos nomes de funções. Eu estava pensando em ir com lowerCamelCase em funções de ligação interna (que chamei de privadas na minha pergunta).
JeffV
3
@ Chris Lutz, eu concordo, de todo coração. Sempre que possível, os vars devem ser mantidos no escopo mais restrito. Observe que na verdade existem três escopos que estamos discutindo: local para uma função, local para um módulo (sem ligação externa à variável) e os globais com ligação externa. É comum ter variáveis ​​"globais para um módulo" em sistemas embarcados. Portanto, deve-se tomar cuidado para identificar os globais com ligação externa, para que possam ser mantidos no mínimo e as interações entre os módulos compreendidas. É aqui que o prefixo "g_" é útil.
11139 JeffV
46
Eu gosto de prefixar variáveis ​​globais com //.
plafer

Respostas:

127

A coisa mais importante aqui é consistência. Dito isto, sigo a convenção de codificação GTK +, que pode ser resumida da seguinte forma:

  1. Todas as macros e constantes em maiúsculas: MAX_BUFFER_SIZE, TRACKING_ID_PREFIX.
  2. Nomes de estruturas e typedef em camelcase: GtkWidget, TrackingOrder.
  3. Funções que operam em estruturas: estilo C clássico: gtk_widget_show(), tracking_order_process().
  4. Ponteiros: nada extravagante aqui: GtkWidget *foo, TrackingOrder *bar.
  5. Variáveis ​​globais: apenas não use variáveis ​​globais. Eles são maus.
  6. Funções que estão lá, mas não devem ser chamadas diretamente, ou têm usos obscuros, ou qualquer outra coisa: um ou mais sublinhados no início: _refrobnicate_data_tables(), _destroy_cache().
axel_c
fonte
13
No ponto seis, prefiro usar statice pular o prefixo do módulo; portanto, se gtk_widget_show()fosse uma função com escopo de arquivo, ela se tornaria simplesmente widget_show()com a classe de armazenamento estático adicionada.
August Karlstrom
27
Nota adicional sobre o ponto 6: o padrão C possui algumas regras sobre a reserva de nomes que começam com _a implementação e uso futuro. Existem algumas exceções nos nomes que começam com, _mas na minha opinião não vale a pena memorizar. Uma regra segura a seguir é nunca usar nomes que começam com _seu código. Entrada relevante da FAQ C: c-faq.com/~scs/cgi-bin/faqcat.cgi?sec=decl#namespace
jw013
5
O número 2 é mais especificamente a caixa superior do camelo ou a caixa pascal . A caixa de camelo ou caixa de camelo inferior usa minúscula na primeira letra.
Clint Pachl #
9
E as variáveis ​​locais com várias palavras? my_var ou myVar?
Dean Gurvitz
4
Global variables: just don't use global variables. They are evil.- a menos que você esteja trabalhando no projeto incorporado e tenha 1024 bytes de RAM e CPU de 8MHz.
Kamil
30

"Ponteiros estruturais" não são entidades que precisam de uma cláusula de convenção de nomenclatura para cobri-los. Eles são apenas struct WhatEver *. NÃO esconda o fato de que há um ponteiro envolvido com um typedef inteligente e "óbvio". Não serve para nada, é mais demorado para digitar e destrói o equilíbrio entre declaração e acesso.

descontrair
fonte
29
+1 para o item "não oculte ponteiros" - mesmo que essa resposta ainda não resolva o restante da pergunta.
Jonathan Leffler
1
@ unwind, tendo a concordar. No entanto, às vezes um ponteiro não pretende ser desreferenciado externo e é mais um identificador para o consumidor do que um ponteiro real para uma estrutura que ele usará. Foi para isso que eu deixei o TitleCasePtr. typedef struct {campos} MyStruct, * MyStructPtr;
11409 JeffV
Estou removendo o TitleCasePtr, é uma distração para a pergunta real.
11409 JeffV
1
-1 desde que uma declaração do tipo ponteiro reduz a desordem, especialmente em assinaturas de funções, e o "desequilíbrio" entre declaração e acesso aparece apenas no arquivo de implementação - o cliente não (não deve) acessar diretamente os membros do campo.
August Karlstrom
1
@AugustKarlstrom Fine. Eu não entendo o que há de "único" no arquivo de implementação, não é esse código também? Não interpretei a pergunta como sendo apenas sobre nomes "externos". Todo o código é "implementação" em algum nível.
Descontraia-se em
17

Bem, em primeiro lugar, C não possui funções públicas / privadas / virtuais. Isso é C ++ e tem convenções diferentes. Em C, normalmente você tem:

  • Constantes em ALL_CAPS
  • Sublinhados para delimitar palavras em estruturas ou nomes de funções, quase nunca você vê casos de camelo em C;
  • structs, typedefs, uniões, membros (de uniões e estruturas) e valores de enum geralmente estão em letras minúsculas (na minha experiência), em vez da convenção C ++ / Java / C # / etc de tornar a primeira letra uma maiúscula, mas acho que é possível em C também.

C ++ é mais complexo. Eu vi uma mistura real aqui. Camel case para nomes de classe ou minúsculas + sublinhados (case camel é mais comum na minha experiência). As estruturas são usadas raramente (e geralmente porque uma biblioteca as exige, caso contrário, você usaria classes).

cleto
fonte
@ Cletus, eu percebo isso. Por particular, quero dizer funções que não são expostas externamente no cabeçalho do módulo e não devem ser usadas por código externo ao módulo. Público seriam funções da API do módulo destinadas a serem usadas externamente.
11139 JeffV
3
Você pode considerar as funções estáticas como privadas; a pergunta não menciona virtual. Mas +1 para 'raramente vê caso de camelo em C'.
12139 Jonathan Leffler
2
Eu acho que Jeff quis dizer external linkage"funções públicas" e internal linkage"funções privadas".
Pmg
1
Vi constantes começando com ak e em: kBufferSize. Não tenho certeza de onde isso vem.
11139 JeffV
2
ALL_CAPStambém é frequentemente usado para valores de enumeração.
caf
14

Você sabe, eu gosto de mantê-lo simples, mas claro ... Então, aqui está o que eu uso, em C:

  • Variáveis ​​Triviais : i,n,c(. Apenas uma carta Se uma letra que não está claro, em seguida, torná-lo uma variável local), etc ...
  • Variáveis ​​locais :lowerCamelCase
  • Variáveis ​​globais :g_lowerCamelCase
  • Variáveis ​​Const :ALL_CAPS
  • Variáveis ​​de ponteiro : adicione p_a ao prefixo. Para variáveis ​​globais, seria gp_var, para variáveis ​​locais p_var, para variáveis ​​const p_VAR. Se ponteiros distantes forem usados, use umfp_ vez de p_.
  • Estruturas : ModuleCamelCase(Módulo = nome completo do módulo ou abreviação de 2-3 letras, mas ainda emCamelCase .)
  • Variáveis ​​de membro de estrutura :lowerCamelCase
  • Enums :ModuleCamelCase
  • Valores Enum :ALL_CAPS
  • Funções Públicas :ModuleCamelCase
  • Funções Privadas :CamelCase
  • Macros :CamelCase

Digitei minhas estruturas, mas usei o mesmo nome para a tag e para o typedef. A tag não deve ser usada com frequência. Em vez disso, é preferível usar o typedef. Também encaminhar declarar o typedef no cabeçalho do módulo público para encapsulamento e para que eu possa usar o nome typedef na definição.

struct Exemplo completo :

typdef struct TheName TheName;
struct TheName{
    int var;
    TheName *p_link;
};
SeanRamey
fonte
Não sei nada sobre a estrutura qt, mas você pode escrever seu código em qualquer formato de estilo que desejar. Nada está impedindo você, até onde eu sei.
SeanRamey
10

Codificação em C #, java, C, C ++ e C objetivo ao mesmo tempo, adotei uma convenção de nomenclatura muito simples e clara para simplificar minha vida.

Em primeiro lugar, ele conta com o poder dos IDEs modernos (como eclipse, Xcode ...), com a possibilidade de obter informações rápidas ao passar o mouse ou clicar com a tecla Ctrl ... Aceitando isso, suprimi o uso de qualquer prefixo, sufixo e outros marcadores que são simplesmente fornecidos pelo IDE.

Então, a convenção:

  • Qualquer nome DEVE ser uma frase legível explicando o que você tem. Como "esta é a minha convenção".
  • Em seguida, 4 métodos para obter uma convenção de uma frase:
    1. THIS_IS_MY_CONVENTION para macros, membros da enumeração
    2. ThisIsMyConvention para nome do arquivo, nome do objeto (classe, estrutura, enum, união ...), nome da função, nome do método, typedef
    3. this_is_my_convention variáveis ​​globais e locais,
      parâmetros, elementos struct e union
    4. thisismyconvention [opcional] variáveis ​​muito locais e temporárias (como um índice de loop for ())

E é isso.

class MyClass {
    enum TheEnumeration {
        FIRST_ELEMENT,
        SECOND_ELEMENT,
    }

    int class_variable;

    int MyMethod(int first_param, int second_parameter) {
        int local_variable;
        TheEnumeration local_enum;
        for(int myindex=0, myindex<class_variable, myindex++) {
             localEnum = FIRST_ELEMENT;
        }
    }
}
Luc Fourestier
fonte
8

Eu recomendaria não misturar camel case e sublinhar a separação (como você propôs para os membros struct). Isso é confuso. Você pensaria, ei, eu tenho, get_lengthentão eu provavelmente deveria ter make_subsete então você descobrirá que é realmente makeSubset. Use o princípio de menor espanto e seja consistente.

Acho CamelCase útil para digitar nomes, como estruturas, typedefs e enumerações. Isso é tudo, no entanto. Para todo o resto (nomes de funções, nomes de membros de estrutura, etc.) eu uso underscore_separation.

Eli Bendersky
fonte
1
Sim, a principal coisa sobre qualquer convenção de nomenclatura é previsibilidade e consistência. Além disso, como a própria biblioteca C usa todas as letras minúsculas com _ para espaçamento, eu recomendaria usar isso apenas para que você não precise lidar com duas convenções de nomenclatura diferentes em um projeto (supondo que você não escreva um wrapper em torno da libc para criar -lo em conformidade com a sua nomeação .. mas isso é bruto)
Earlz
Ele também usa typedefs com um " t" no final, mas não vejo ninguém recomendando isso. De fato, a biblioteca padrão é até inconsistente: div_t (stdlib.h) é uma estrutura e também é tm (time.h). Além disso, dê uma olhada nos membros tm struct, todos eles são prefixados com tm, o que parece inútil e feio (IMO).
JeffV
1
"Eu acho o CamelCase útil para digitar nomes ..." Se você começar com letras maiúsculas, na verdade é PascalCase.
Tagc
7

Aqui está um (aparentemente) incomum, que eu achei útil: nome do módulo no CamelCase, depois um sublinhado, depois o nome da função ou do escopo do arquivo no CamelCase. Então, por exemplo:

Bluetooth_Init()
CommsHub_Update()
Serial_TxBuffer[]
Steve Melnikoff
fonte
2
Não é tão incomum, mas muito útil.
chux - Restabelece Monica
3

Estou confuso com uma coisa: você está planejando criar uma nova convenção de nomenclatura para um novo projeto. Geralmente, você deve ter uma convenção de nomes que abranja toda a empresa ou equipe. Se você já possui projetos com qualquer forma de convenção de nomenclatura, não deve alterar a convenção para um novo projeto. Se a convenção acima é apenas uma codificação de suas práticas existentes, você é de ouro. Quanto mais difere da existente fato de fato padrões mais difícil será obter participação no novo padrão.

Sobre a única sugestão que gostaria de acrescentar é que gosto de _t no final dos tipos no estilo de uint32_t e size_t. É muito c-ish para mim, embora alguns possam reclamar, é apenas um húngaro "reverso".

jmucchiello
fonte
3
Bem, as convenções aqui estão em todo lugar e são inconsistentes, razão pela qual estou pretendendo documentar uma. Além disso, é por isso que estou perguntando. Para ver qual é o consenso da comunidade.
11409 JeffV
Eu entendo essa dor. Mas deve haver algum subconjunto de suas convenções existentes que seja mais popular. Você deve começar por aí e não em uma página da Internet aleatória na Internet. Você também deve perguntar aos seus outros desenvolvedores o que eles considerariam bons.
jmucchiello
7
Acredito que nomes de tipos terminados em _t são reservados pelo padrão POSIX.
caf
4
Os nomes que terminam com _t são reservados. Consulte gnu.org/software/libc/manual/html_node/Reserved-Names.html , "Os nomes que terminam com '_t' são reservados para nomes de tipos adicionais."
Etienne
2

Você também deve pensar na ordem das palavras para completar automaticamente o nome .

Uma boa prática: nome da biblioteca + nome do módulo + ação + assunto

Se uma peça não for relevante, basta ignorá-la, mas pelo menos um nome de módulo e uma ação sempre devem ser apresentados.

Exemplos:

  • nome da função: os_task_set_prio, list_get_size,avg_get
  • define (aqui geralmente nenhuma parte de ação ):OS_TASK_PRIO_MAX
Gábor Kiss-Vámosi
fonte
0

Pode haver muitos, principalmente IDEs, ditando algumas tendências e as convenções de C ++ também estão avançando. Para C geralmente:

  • UNDERSCORED_UPPER_CASE (definições de macro, constantes, membros da enumeração)
  • underscored_lower_case (variáveis, funções)
  • CamelCase (tipos personalizados: estruturas, enumerações, uniões)
  • uncappedCamelCase (estilo Java oppa)
  • UnderScored_CamelCase (variáveis, funções sob o tipo de namespaces)

A notação húngara para globais é boa, mas não para tipos. E mesmo para nomes triviais, use pelo menos dois caracteres.

renonsz
fonte
-1

Eu acho que isso pode ajudar para iniciantes: Convenção de nomenclatura de variáveis ​​em c

  1. Você precisa usar Caractere alfabético (az, AZ), Dígito (0-9) e Sob Pontuação (_). Não é permitido usar caracteres especiais como:%, $, #, @ etc. Portanto, você pode usar o user_name como variável, mas não pode usar o user & name .
  2. Não é possível usar espaço em branco entre as palavras. Portanto, você pode usar user_name ou nome de usuário ou nome de usuário como variável, mas não pode usar nome de usuário .
  3. Não é possível começar a nomear com dígito. Portanto, você pode usar user1 ou user2 como variável, mas não pode usar 1user .
  4. É uma linguagem que diferencia maiúsculas de minúsculas. Maiúsculas e minúsculas são significativas. Se você usar uma variável como nome de usuário , não poderá usar USERNAME ou Nome de usuário de para uso pai.
  5. Você não pode usar nenhuma palavra-chave (char, int, if, for, while etc) para declaração de variável.
  6. O padrão ANSI reconhece um comprimento de 31 caracteres para um nome de variável
Amranur Rahman
fonte
Esta publicação visa claramente discutir convenções de nomenclatura , não restrições . O que você listou são coisas que você nem pode fazer porque são erros de sintaxe.
Chase