Pergunta

Eu tenho trabalhado com um número de projetos C durante a minha carreira de programação e as estruturas de arquivos de cabeçalho geralmente caem em uma das estes dois padrões:

  1. Um arquivo de cabeçalho contendo todos os protótipos de função
  2. Um arquivo .h para cada arquivo .c, contendo protótipos para as funções definidas em apenas esse módulo.

As vantagens da opção 2 é óbvio para mim - que torna mais barato para compartilhar o módulo entre vários projetos e faz dependências entre os módulos mais fácil ver

.

Mas quais são as vantagens da opção 1? Deve ter algumas vantagens caso contrário não seria tão popular.


Esta questão se aplica a C ++, bem como C, mas eu nunca vi # 1 em um C ++ projeto.

A colocação de #defines, structs etc. também varia, mas para esta pergunta que eu gostaria de focar em protótipos de função.

Foi útil?

Solução

Opção 1 permite ter de modo que você tem que incluir / search apenas um arquivo em vez de ter de incluir / search muitos arquivos todas as definições em um só lugar. Esta vantagem é mais evidente se o seu sistema é fornecido como uma biblioteca para um terceiro - eles não se importam muito sobre sua estrutura de biblioteca, eles só querem ser capaz de usá-lo

.

Outras dicas

Eu acho que a principal motivação para a # 1 é ... preguiça. As pessoas pensam que é demasiado difícil de gerir as dependências que dividir as coisas em arquivos separados pode fazer mais óbvio, e / ou acho que é de alguma forma "um exagero" para ter arquivos separados para tudo.

Pode também, é claro, muitas vezes, ser um caso de "razões históricas", onde o programa ou projeto cresceu de algo pequeno, e ninguém teve tempo para refatorar os arquivos de cabeçalho.

Outra razão para usar um .h diferente para cada .c é tempo de compilação. Se houver apenas um .h (ou se há mais deles, mas você está incluindo todos eles em cada arquivo .c), cada vez que você fizer uma alteração no arquivo .h, você vai ter que recompilar cada arquivo .c. Este, em um projeto grande, pode representar uma quantidade valiosa de tempo a ser perdido, o que também pode quebrar o seu fluxo de trabalho.

  • 1 é apenas desnecessário. Eu não posso ver uma boa razão para fazê-lo, e muito para evitá-lo.

três regras para seguir # 2 e não têm problemas:

  • Comece cada arquivo de cabeçalho com um

    #ifndef _HEADER_Namefile
    #define _HEADER_Namefile_
    

no final do arquivo

    #endif

Isso permitirá que você incluir o mesmo arquivo de cabeçalho várias vezes no mesmo módulo (innadvertely pode acontecer), sem causar qualquer problema.

  • Você não pode ter definições sobre seus arquivos de cabeçalho ... e isso é algo que todo mundo pensa que ele / ela sabe, sobre protótipos de função, mas quase sempre ignora para variáveis ??globais. Se você quiser uma variável global, que, por definição, deve ser visível fora está definindo módulo C, utilize a palavra-chave externo:

    extern unsigned long G_BEER_COUNTER;
    

que instrui o compilador que o símbolo G_BEER_COUNTER é realmente um unsigned long (assim, funciona como uma declaração), que em algum outro módulo terá é adequada definição / inicialização. (Isso também permite que o vinculador para manter o / table símbolo não resolvido resolvido.) A definição real (mesmo comunicado, sem extern) vai no arquivo módulo .c.

  • necessidade absoluta somente no comprovada você incluir outros cabeçalhos dentro de um arquivo de cabeçalho. incluir declarações só deve ser visível em arquivos .c (os módulos). Que lhe permite interpretar melhor os dependecies, e encontrar / a resolver problemas.

Eu recomendaria uma abordagem híbrida: fazer um cabeçalho separado para cada componente do programa que poderia concebivelmente ser usado de forma independente, em seguida, fazendo um cabeçalho de projeto que inclui todos eles. Dessa forma, cada arquivo de origem só precisa incluir um cabeçalho (sem necessidade de ir atualizando todos os seus arquivos de origem se você refatorar componentes), mas você manter uma organização lógica para suas declarações e torná-lo fácil de reutilizar o seu código.

Há também eu acredito que uma terceira opção: a cada .c tem seu próprio .h, mas há também um .h que inclui todos os outros arquivos .h. Isto traz o melhor dos dois mundos, à custa de manter um .h até à data, no entanto, que poderia feito automaticamente.

Com esta opção, internamente você usar os arquivos .h individuais, mas um 3o partido apenas pode incluir o arquivo .h abrangente.

Quando você tem um projeto muito grande com centenas / milhares de arquivos de cabeçalho pequenas, verificação de dependência e compilação pode desacelerar significativamente como lotes de pequenos arquivos devem ser abertos e lidos. Este problema pode ser muitas vezes resolvido usando cabeçalhos pré-compilados.

Em C ++ você iria querer um arquivo de cabeçalho por turma e usar cabeçalhos pré-compilados, como mencionado acima.

Um arquivo de cabeçalho para um projeto inteiro é inviável a menos que o projeto é extremamente pequeno - como uma atribuição de escola

Isso depende de quanta funcionalidade está em um arquivo de cabeçalho / fonte. Se você precisa incluir 10 arquivos apenas para, digamos, tipo algo, é ruim.

Por exemplo, se eu quiser usar vetores STL Eu só incluem e eu não ligo para o que são necessários internos para o vetor a ser utilizado. GCC inclui 8 outros cabeçalhos - alocador, algobase, construir, não inicializada, vector e bvector. Seria doloroso para incluir todos aqueles 8 apenas para uso vetor, concorda?

Porém, biblioteca conectores internos deve ser tão escassa quanto possível. Compiladores são mais felizes se eles não incluem coisas desnecessárias.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top