#include em .h ou .c / .cpp?

118

Ao codificar em C ou C ++, onde devo ter o #include 's?

callback.h:

#ifndef _CALLBACK_H_
#define _CALLBACK_H_

#include <sndfile.h>
#include "main.h"

void on_button_apply_clicked(GtkButton* button, struct user_data_s* data);
void on_button_cancel_clicked(GtkButton* button, struct user_data_s* data);

#endif

callback.c:

#include <stdlib.h>
#include <math.h>

#include "config.h"

#include "callback.h"
#include "play.h"

void on_button_apply_clicked(GtkButton* button, struct user_data_s* data) {
  gint page;
  page = gtk_notebook_get_current_page(GTK_NOTEBOOK(data->notebook));

  ...

Todas as inclusões devem estar em .h ou .c / .cpp, ou em ambos, como fiz aqui?

Louise
fonte
2
Deixe-me virar isso e perguntar: qual foi o seu critério para decidir colocar sndfile.h e main.h em callback.h?
Owen S.

Respostas:

161

Coloque o máximo que puder no .ce o mínimo possível no .h. As inclusões no .csão incluídas apenas quando aquele arquivo é compilado, mas as inclusões no .hdevem ser incluídas por cada arquivo que o utiliza.

Brendan Long
fonte
6
É verdade, mas não #ifndef _CALLBACK_H_impede o compilador de processá-lo mais de uma vez?
hytromo de
11
@ user9379 Isso impedirá que seja incluído mais de uma vez por arquivo .c ou .cpp. Cada arquivo .c ou .cpp geralmente é criado individualmente, o que significa que um .h será analisado novamente para cada arquivo .c ou .cpp que você compilar.
Brendan Long
2
Acho que o principal motivo para colocar o mínimo possível no .hé para evitar em alguns casos um erro por causa de um laço de inclusão. Exemplo: duas classes precisam uma da outra para suas implementações, mas não para suas declarações. Colocar ambos os includes no .cpps evitará um erro.
Codoscope
1
@ Qu'est-cet'yont Essa é a razão pela qual você não pode colocar certas coisas nos arquivos .h. Essa resposta é sobre por que você deve colocar ainda menos do que isso.
Brendan Long
@BrendanLong, eu vejo, embora, no meu sentido, incluir várias vezes o mesmo cabeçalho não importe se você colocar as macros corretas dentro para incluir o conteúdo apenas uma vez. Portanto, acho que colocar ainda menos é reduzir as probabilidades de obter um erro no futuro com modificações do código.
Codoscope
55

A única vez em que você deve incluir um cabeçalho em outro arquivo .h é se precisar acessar uma definição de tipo nesse cabeçalho; por exemplo:

#ifndef MY_HEADER_H
#define MY_HEADER_H

#include <stdio.h>

void doStuffWith(FILE *f); // need the definition of FILE from stdio.h

#endif

Se o cabeçalho A depender do cabeçalho B, como no exemplo acima, o cabeçalho A deverá incluir o cabeçalho B diretamente. fazer nÃO tentar encomendar o seu inclui no arquivo .c para satisfazer dependências (isto é, incluindo cabeçalho B antes de cabeçalho A); essa é uma grande pilha de azia esperando para acontecer. Quero dizer. Já estive nesse filme várias vezes, e sempre terminava com Tóquio em chamas.

Sim, isso pode resultar em arquivos sendo incluídos várias vezes, mas se eles tiverem guardas de inclusão apropriados configurados para proteger contra vários erros de declaração / definição, então alguns segundos extras de tempo de compilação não valem a pena se preocupar. Tentar gerenciar dependências manualmente é um pé no saco.

Obviamente, você não deve incluir arquivos desnecessários .

John Bode
fonte
10

Coloque o máximo possível de inclusões em seu cpp e apenas aquelas que são necessárias para o arquivo hpp no ​​hpp. Acredito que isso ajudará a acelerar a compilação, pois os arquivos hpp terão menos referências cruzadas.

Considere também o uso de declarações de encaminhamento em seu arquivo hpp para reduzir ainda mais a cadeia de dependência de inclusão.

Parappa
fonte
1
Oo. A coisa das declarações futuras é interessante.
Brendan Long
Parappa, as declarações de encaminhamento são muito úteis em cenários de referência circular. Mas seriam uma boa prática em outros cenários? (Eu sou novo em C ++, então estou perguntando honestamente)
Dzyann
5

Se eu #include <callback.h>, não quero ter #includemuitos outros arquivos de cabeçalho para fazer meu código compilar. Em callback.hvocê deve incluir tudo o necessário para compilar contra ele. Mas nada mais.

Considere se usar declarações de encaminhamento em seu arquivo de cabeçalho (como class GtkButton;) será suficiente, permitindo que você reduza o número de #includediretivas no cabeçalho (e, por sua vez, meu tempo de compilação e complexidade).

Johnsyweb
fonte
Discordo. Incluir o mundo inteiro em arquivos H aumenta a cadeia de dependências e, portanto, os tempos de compilação.
John Dibling
Minha resposta não recomendou incluir o mundo inteiro no arquivo de cabeçalho, sugeri incluir apenas o suficiente para que o usuário da API não tenha que perder tempo procurando dependências.
Johnsyweb