Devo colocar as inclusões no arquivo de cabeçalho ou no arquivo de origem? Se o arquivo de cabeçalho contiver as instruções de inclusão, se eu incluir esse arquivo de cabeçalho em minha fonte, meu arquivo de fonte terá todos os arquivos incluídos que estavam em meu cabeçalho? Ou devo apenas incluí-los apenas no meu arquivo de origem?
107
Respostas:
Só coloque includes em um cabeçalho se o próprio cabeçalho precisar deles.
Exemplos:
size_t
. Em seguida,#include <stddef.h>
no arquivo de cabeçalho .strlen
. Em seguida,#include <string.h>
no arquivo de origem .fonte
size_t
?size_t
oustd::string
?Tem havido um grande desacordo sobre isso ao longo dos anos. Ao mesmo tempo, era tradicional que um cabeçalho apenas declarasse o que estava em qualquer módulo ao qual estava relacionado, portanto, muitos cabeçalhos tinham requisitos específicos para
#include
um determinado conjunto de cabeçalhos (em uma ordem específica). Alguns programadores C extremamente tradicionais ainda seguem esse modelo (religiosamente, pelo menos em alguns casos).Mais recentemente, há um movimento no sentido de tornar a maioria dos cabeçalhos autônomos. Se esse cabeçalho exigir algo mais, o próprio cabeçalho lida com isso, garantindo que tudo o que for necessário seja incluído (na ordem correta, se houver problemas de pedido). Pessoalmente, eu prefiro isso - especialmente quando a ordem dos cabeçalhos pode ser importante, ela resolve o problema uma vez, em vez de exigir que todos que a usam resolvam o problema novamente.
Observe que a maioria dos cabeçalhos deve conter apenas declarações. Isso significa que adicionar um cabeçalho desnecessário não deve (normalmente) ter qualquer efeito em seu executável final. O pior que acontece é que torna a compilação um pouco mais lenta.
fonte
Seus
#include
s devem ser de arquivos de cabeçalho, e cada arquivo (fonte ou cabeçalho) deve#include
conter os arquivos de cabeçalho de que necessita. Arquivos de cabeçalho devem#include
o mínimo de arquivos de cabeçalho necessário, e os arquivos de origem também, embora não sejam tão importantes para os arquivos de origem.O arquivo de origem terá os cabeçalhos it
#include
s, e os cabeçalhos they#include
, e assim por diante, até a profundidade máxima de aninhamento. É por isso que você não quer supérfluo#include
s em arquivos de cabeçalho: eles podem fazer com que um arquivo de origem inclua muitos arquivos de cabeçalho de que não precisa, tornando a compilação mais lenta.Isso significa que é perfeitamente possível que os arquivos de cabeçalho sejam incluídos duas vezes e isso pode ser um problema. O método tradicional é colocar "incluir guardas" em arquivos de cabeçalho, como este para o arquivo foo.h:
fonte
A abordagem que evoluí para mais de vinte anos é esta;
Considere uma biblioteca.
Existem vários arquivos C, um arquivo H interno e um arquivo H externo. Os arquivos C incluem o arquivo H interno. O arquivo H interno inclui o arquivo H externo.
Você vê que no POV dos compiladores, conforme ele compila um arquivo C, há uma hierarquia;
externo -> interno -> código C
Essa é a ordem correta, pois o externo é tudo o que um terceiro precisa para usar a biblioteca. Aquilo que é interno é necessário para compilar o código C.
fonte
Se o arquivo de cabeçalho A for
#includes
arquivos de cabeçalho B e C, todos os arquivos de origem que#includes
A também receberão B e C#included
. O pré-processador literalmente apenas executa a substituição de texto: em qualquer lugar ele encontra um texto que diz#include <foo.h>
que o substitui pelo texto dofoo.h
arquivo.Existem diferentes opiniões sobre se você deve colocar
#includes
cabeçalhos ou arquivos de origem. Pessoalmente, prefiro colocar todos#includes
no arquivo de origem por padrão, mas quaisquer arquivos de cabeçalho que não possam ser compilados sem outros cabeçalhos de pré-requisito devem ser#include
esses próprios cabeçalhos.E cada arquivo de cabeçalho deve conter uma proteção de inclusão para evitar que seja incluído várias vezes.
fonte
Em alguns ambientes, a compilação será mais rápida se incluirmos apenas os arquivos de cabeçalho necessários. Em outros ambientes, a compilação será otimizada se todos os arquivos de origem puderem usar a mesma coleção primária de cabeçalhos (alguns arquivos podem ter cabeçalhos adicionais além do subconjunto comum). O ideal é que os cabeçalhos sejam construídos de forma que várias operações #include não tenham efeito. Pode ser bom cercar as instruções #include com verificações para a proteção de inclusão do arquivo a ser incluído, embora isso crie uma dependência do formato dessa proteção. Além disso, dependendo do comportamento de cache de arquivos do sistema, um #include desnecessário cujo alvo acaba sendo completamente # definido pode não demorar muito.
Outra coisa a considerar é que se uma função leva um ponteiro para uma estrutura, pode-se escrever o protótipo como
sem uma definição para BAR_s tendo que estar no escopo. Uma abordagem muito útil para evitar inclusões desnecessárias.
PS - em muitos de meus projetos, haverá um arquivo que se espera que cada módulo inclua #include, contendo coisas como typedefs para tamanhos inteiros e algumas estruturas e uniões comuns [por exemplo
(Sim, eu sei que teria problemas se mudasse para uma arquitetura big-endian, mas como meu compilador não permite estruturas anônimas em uniões, usar identificadores nomeados para os bytes dentro da união exigiria que eles fossem acessados como theUnion.b.b1 etc. o que parece bastante irritante.
fonte
Faça todos os seus arquivos para que possam ser construídos usando apenas o que incluem. Se você não precisa incluir em seu cabeçalho, remova-o. Em um grande projeto, se você não mantiver essa disciplina, ficará aberto a quebrar uma compilação inteira quando alguém remover um include de um arquivo de cabeçalho que está sendo usado por um consumidor desse arquivo e nem mesmo pelo cabeçalho.
fonte
Seu arquivo de origem terá as instruções de inclusão se você colocá-lo no cabeçalho. No entanto, em alguns casos, seria melhor colocá-los no arquivo de origem.
Lembre-se de que se você incluir esse cabeçalho em qualquer outra fonte, eles também obterão as inclusões do cabeçalho, e isso nem sempre é desejável. Você só deve incluir o material onde for usado.
fonte
Você só deve incluir arquivos em seu cabeçalho que você precisa para declarar constantes e declarações de função. Tecnicamente, essas inclusões também serão incluídas em seu arquivo de origem, mas para fins de clareza, você só deve incluir em cada arquivo os arquivos que realmente precisa usar. Você também deve protegê-los em seu cabeçalho de inclusão múltipla, desta forma:
Isso evita que o cabeçalho seja incluído várias vezes, resultando em um erro do compilador.
fonte