Convenções de nomenclatura usadas para variáveis ​​e funções em C [fechado]

13

A codificação de um grande projeto no CI encontrou um problema. Se eu continuar escrevendo mais código, haverá um momento em que será difícil para mim organizar o código. Quero dizer que a nomeação de funções e variáveis ​​para diferentes partes do programa pode parecer confusa.

Então, eu estava pensando se existem convenções de nomenclatura úteis que eu possa usar para variáveis ​​e funções C?

A maioria dos idiomas sugere uma convenção de nomenclatura. Mas para C, a única coisa que li até agora é que os nomes devem ser descritivos para facilitar a leitura do código.

EDITAR:

Exemplos de alguns exemplos de convenções de nomenclatura sugeridas:

Eu li mais algumas convenções de nomenclatura para java em algum lugar, mas não conseguia lembrar onde.

Aseem Bansal
fonte
Cite alguns exemplos de idiomas com convenções de nomenclatura sugeridas. E onde podemos encontrar essas convenções de nomenclatura.
Philip
@Philip Exemplos adicionados
Aseem Bansal
1
Não deve haver um problema com variáveis, pois você não usa globais. E para nomes de funções: se o nome do módulo é order.c, você pode nomear as funções order_add(), order_del()e tal. Pode haver sistemas antigos que informam que o nome deve ser exclusivo nos 8 primeiros caracteres. Quando você muda para o c ++ mais tarde por acidente, adora escrever order::add()e order::del()depois.
ott--

Respostas:

17

Se eu continuar escrevendo mais código, haverá um momento em que será difícil para mim organizar o código.

Esse é o seu problema: acerte a organização e o estilo deve fluir mais facilmente.

Não espere para organizar seu código: mantenha seu código organizado à medida que avança. Embora a linguagem não faça isso por você, o código ainda deve ser organizado em módulos com baixo acoplamento e alta coesão.

Esses módulos, naturalmente, fornecem um espaço para nome. Abrevie o nome do módulo (se for longo) e prefixe os nomes das funções com seu módulo para evitar colisões.

No nível dos identificadores individuais, eles estão aproximadamente em ordem crescente de subjetividade:

  1. escolha uma convenção e fique com ela
    • por exemplo, function_like_this(struct TypeLikeThis variable)é comum
  2. definitivamente evitar a notação húngara (desculpe JNL)

    • a menos que você esteja disposto a usá-lo como pretendido originalmente, o que significa a notação de aplicativos de Simonyi em vez da terrível versão de sistemas

      Por quê? Eu poderia escrever um ensaio sobre isso, mas, em vez disso, sugiro que você leia este artigo de Joel Spolsky e, em seguida, procure um pouco mais, se estiver interessado. Há um link para o artigo original de Simonyi na parte inferior.

  3. evite typedefs de ponteiro, a menos que sejam tipos de cookies genuinamente opacos - eles apenas confundem as coisas

    struct Type *ok;
    typedef struct Type *TypePtr;
    TypePtr yuck;
    

    O que quero dizer com um tipo de cookie opaco ? Quero dizer algo usado dentro de um módulo (ou biblioteca, ou o que seja) que deve ser passado para o código do cliente, mas esse código do cliente não pode ser usado diretamente. Apenas passa de volta para a biblioteca.

    Por exemplo, uma biblioteca de banco de dados pode expor uma interface como

    /* Lots of buffering, IPC and metadata magic held in here.
       No, you don't get to look inside. */
    struct DBContextT;
    /* In fact, you only ever get a pointer, so let's give it a nice name */
    typedef struct DBContexT *DBContext;
    
    DBContext db_allocate_context(/*maybe some optional flags?*/);
    void db_release_context(DBContext);
    int db_connect(DBContext, const char *connect);
    int db_disconnect(DBContext);
    int db_execute(DBContext, const char *sql);
    

    Agora, o contexto é opaco ao código do cliente, porque você não pode olhar para dentro. Você acabou de devolvê-lo à biblioteca. Algo como FILEtambém é opaco, e um descritor de arquivo inteiro também é um cookie , mas não é opaco.


Uma nota sobre design

Usei a frase baixo acoplamento e alta coesão acima, sem explicação, e me sinto um pouco mal com isso. Você pode procurá-lo e provavelmente encontrar bons resultados, mas tentarei abordar brevemente (novamente, eu poderia escrever um ensaio, mas tentarei não).

A biblioteca do DB esboçada acima mostra baixo acoplamento porque expõe uma pequena interface para o mundo externo. Ocultando seus detalhes de implementação (em parte com o truque de cookie opaco), impede que o código do cliente dependa desses detalhes.

Imagine, em vez do cookie opaco, declaramos a estrutura do contexto para que seu conteúdo seja visível, e isso inclui um descritor de arquivo de soquete para uma conexão TCP ao banco de dados. Se posteriormente mudarmos a implementação para oferecer suporte ao uso de um segmento de memória compartilhada quando o banco de dados estiver em execução na mesma máquina, o cliente precisará ser recompilado em vez de apenas vinculado novamente. Pior ainda, o cliente poderia ter começado a usar o descritor de arquivo, por exemplo, chamando setsockoptpara alterar o tamanho padrão do buffer, e agora também precisa de uma alteração no código. Todos esses detalhes devem estar ocultos dentro do nosso módulo, sempre que possível, e isso proporciona baixo acoplamento entre os módulos.

O exemplo também mostra alta coesão , pois todos os métodos no módulo estão relacionados à mesma tarefa (acesso ao banco de dados). Isso significa que apenas o código que precisa saber sobre os detalhes da implementação (ou seja, o conteúdo do nosso cookie) realmente tem acesso a eles, o que simplifica a depuração.

Você também pode ver que ter uma única preocupação facilitou a escolha de um prefixo para agrupar essas funções.

Agora, dizer que este exemplo é bom é fácil (especialmente porque nem sequer está completo), mas não ajuda imediatamente. O truque é observar, enquanto você escreve e estende seu código, para funções que fazem coisas semelhantes ou operam nos mesmos tipos (que podem ser candidatos ao seu próprio módulo) e também para funções que fazem muitas coisas separadas que não são ' Não está realmente relacionado e pode ser candidato à divisão.

Sem utilidade
fonte
Você pode me ajudar a entender por que o húngaro é evitado? Apenas curioso para saber mais sobre isso. :)
JNL
@JNL: Um comentário é muito curto para explicar corretamente. Sugiro que você a publique como uma nova pergunta.
Bart van Ingen Schenau
with low coupling and high cohesion. O que isso significa? E, por favor, explique sobre os tipos de cookies opacos. Eu não tenho idéia o que isso significa.
Aseem Bansal
Tentei abordar os dois brevemente e falhei francamente na brevidade. Esperemos que você deve começar.
Inútil
Estou respondendo depois de alguns dias. Desculpe por isso. Eu li a sua descrição de low coupling and high cohesion. Então, basicamente significa encapsular as coisas quando posso e deve ser feito de uma maneira que as funções que realmente precisam tenham acesso. Algumas coisas passaram pela minha cabeça, mas ainda acho que entendi seu ponto.
Aseem Bansal
5

Na minha opinião, 90% do problema de nomeação é resolvido se você tiver três coisas em mente: a) torne os nomes de variáveis ​​e funções o mais descritivos possível, b) seja consistente em todo o código (por exemplo, se uma função for denominada addNumbers, a a segunda função deve ser denominada multiplyNumbers e não numbersMul) ec) tente abreviar os nomes, se possível, pois precisamos digitá-los.

Dito isto, se você quiser dar uma olhada em outros aspectos deste tópico, a página da Wikipedia sobre Convenções de Nomenclatura tem uma boa lista de itens que você deve ter em mente. Ele também possui uma seção em C e C ++:

Em C e C ++, as palavras-chave e os identificadores de bibliotecas padrão são em minúsculas. Na biblioteca padrão C, os nomes abreviados são os mais comuns (por exemplo, isalnum para uma função que testa se um caractere é alfanumérico), enquanto a biblioteca padrão C ++ geralmente usa um sublinhado como separador de palavras (por exemplo, intervalo_de_outros). Os identificadores que representam macros são, por convenção, escritos usando apenas letras maiúsculas e sublinhados (isso está relacionado à convenção em muitas linguagens de programação do uso de identificadores em maiúsculas para constantes). Os nomes que contêm sublinhado duplo ou iniciados com um sublinhado e uma letra maiúscula são reservados para implementação (compilador, biblioteca padrão) e não devem ser usados ​​(por exemplo, reservados__ ou _Reservados). [5] [6] Isso é superficialmente semelhante ao stropping, mas a semântica é diferente:

Daniel Scocco
fonte
3
"tente tornar os nomes curtos, se possível" Use um IDE com preenchimento automático, para que os nomes de suas funções sejam tão longos e descritivos quanto sejam necessários, pois você só precisará digitar uma vez.
Joel
1
@ Joel péssimos conselhos. Nem todo mundo usará o mesmo IDE que você.
James
6
@ James Eles não precisam, eles podem simplesmente usar qualquer IDE decente. Então você não precisa sacrificar a clareza pela produtividade.
Joel
O termo IDE é estendido um pouco mais fino hoje em dia. Tecnicamente, o Notepad ++ é um IDE porque você pode configurá-lo para compilar e executar seu projeto, mas é principalmente um editor de texto. E é preenchido automaticamente.
Philip
5

A única restrição rígida em C é que não há espaços para nome. Portanto, você precisa encontrar uma maneira de diferenciar a função da sua biblioteca rename()do sistema de arquivos da rename()função da sua biblioteca de mídia . A solução usual é um prefixo, como: filesystem_rename()e media_rename().

O outro conselho geral é: mantenha a consistência dentro de um projeto ou equipe. A legibilidade será melhorada.

mouviciel
fonte
+1: isso é especialmente verdade para símbolos exportados em uma biblioteca. "Sinto muito, mas essa biblioteca do sistema de arquivos não acompanha essa biblioteca de mídia, porque ambas têm uma função exportada renomeada.
Residuum
2

SE VOCÊ ESTÁ PROCURANDO UM FORMATO GLOBALMENTE ACEITO

O MISRA / JSF / AUTOSAR cobre quase 100% de todo e qualquer padrão do setor para nomear e organizar o código C / C ++. O problema é que eles não serão livres para se apossar, isto é, cada um dos guias custa algum dinheiro. Eu sei que o livro padrão de codificação MISRA 2008 C / C ++ provavelmente custa cerca de 50 USD.

Você pode pensar nelas como a referência de Harvard para bibliografia e leitura adicional ao escrever um diário. Eu usei o MISRA e é uma boa maneira de nomear suas funções e variáveis ​​e organizá-las para uso adequado.

SE VOCÊ ESTÁ PROCURANDO ALGO TEMPORÁRIO

As referências que você forneceu para Python e Java estão bem, eu acho. Vi pessoas adotando o estilo javadoc comentando, nomeando e organizando o código. De fato, em meu último projeto, tive que escrever código C ++ em funções semelhantes a Java / nomes de variáveis. Duas razões por trás disso:

1) Era aparentemente mais fácil de seguir.

2) Os requisitos do código de produção não atingiram o solo dos padrões críticos do sistema de software de segurança.

3) O código legado estava (de alguma forma) nesse formato.

4) O Doxygen permitiu comentar o Javadoc sytle. Naquele momento, estávamos usando o doxygen para gerar documentação para o pessoal da produção.

Muitos programadores se opõem a isso, mas eu pessoalmente acho que não há nada errado em adotar a função de estilo javadoc / nomeação de variáveis ​​no C / C ++. SIM, é claro que as práticas de organização de seu controle de fluxo, segurança da rosca etc. devem ser abordadas independentemente. No entanto, não sou candidato aqui. Também não sei quão rigorosos são os requisitos de formato de código de produção. Sem desviá-lo para uma área fora do tópico, sugiro que você revise seus requisitos, descubra como você depende de uma convenção de nomenclatura específica e siga uma solução mencionada nas minhas e nas respostas de outras pessoas

Espero que isso tenha ajudado !?

hagubear
fonte
Na verdade, eu estava pedindo isso para códigos C pessoais. Mas vou me lembrar da sua sugestão.
Aseem Bansal
@AseemBansal Pessoal ou profissional, é bom aprender e também colocar no seu currículo :) ... Depende de você.
hagubear
0

Poucas coisas importantes a serem consideradas durante a nomeação seriam;

  1. Observe o tipo actionObject ou ObjectAction. (Objeto não para C. Mas, geralmente, quando você acessa outros idiomas orientados a objetos) Isso deve ajudar

  2. O descanso seria CONSISTENTE, breve e descritivo, com certeza.

  3. Além disso, tenha um único objetivo para cada variável e função definida, por exemplo: Se for para armazenar um valor temporariamente, nomeie-o como nTempVal para int
  4. As variáveis ​​devem ser substantivas e os Métodos, verbais.
JNL
fonte
6
A notação húngara (prefixando uma variável com letras indicando o tipo) não leva ao fim da dor. Felizmente, a maioria ficou fora de moda.
Gort the Robot
@StevenBurnap Estava curioso por que o formato húngaro é evitado? Acredito que foi o que eles nos ensinaram na escola e também vi esse código em alguns locais de trabalho. Qual deles você recomendaria se não fosse húngaro. Graças
JNL
1
A melhor convenção de nomenclatura é apenas uma usada consistentemente, com nomes descritivos e claros, idealmente mantidos relativamente curtos sem abreviação excessiva e evitando prefixos redundantes. A notação húngara tem pouca utilidade real, dificulta a leitura do código e dificulta a alteração de tipos.
Gort the Robot
2
Aqui está uma descrição da intenção original e da abominação que a notação húngara se tornou: joelonsoftware.com/articles/Wrong.html
Residuum
@ Residuum Esse foi um bom link. Ajudou muito. Aprecie isso.
JNL
0

A maioria das respostas é boa, mas quero dizer algumas coisas sobre convenções de nomenclatura para bibliotecas e arquivos incluídos, semelhante ao uso de espaços para nome em outras linguagens como C ++ ou Java:

Se você criar uma biblioteca, encontre um prefixo comum para seus símbolos exportados, ou seja, funções globais, typedefs e variáveis. Isso evitará conflitos com outras bibliotecas e identificará as funções como sendo suas. Este é um pouco de aplicativos notações húngaras.

Talvez vá ainda mais longe e agrupe seus símbolos exportados: libcurl usa curl_ * para símbolos globais, curl_easy_ *, curl_multi_ * e curl_share_ * para as diferentes interfaces. Portanto, além de usar curl_ * para todas as funções, eles adicionaram outro nível de "namespaces" para as diferentes interfaces: chamar uma função curl_easy_ * em um identificador curl_multi_ * agora parece errado, consulte os nomes das funções em http: // curl. haxx.se/libcurl/c/

Mantendo as regras para símbolos exportados, você deve usá-las para funções estáticas em #includearquivos ed: Tente encontrar um prefixo comum para essas funções. Talvez você tenha funções estáticas de utilitários de string em um arquivo chamado "my_string"? Prefixe todas essas funções com my_string_ *.

Resíduo
fonte
Por símbolos exportados, você quer dizer variáveis ​​globais, funções, typedefs etc., se eu estiver correto. Você pode explicar um pouco sobre o agrupamento dos símbolos exportados? Eu pensei que você tivesse explicado isso no parágrafo anterior. O que você adicionou no terceiro parágrafo?
Aseem Bansal