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

118

Lors du codage en C ou C ++, où dois-je avoir les #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));

  ...

Toutes les inclusions devraient-elles être dans le .h ou .c / .cpp, ou les deux comme je l'ai fait ici?

Louise
la source
2
Permettez-moi de renverser la situation et de demander: quels étaient vos critères pour décider de mettre sndfile.h et main.h dans callback.h?
Owen S.

Réponses:

161

Mettez autant que vous le pouvez dans le .cet le moins possible dans le .h. Les inclus dans le .cne sont inclus que lorsque ce fichier est compilé, mais les inclus pour le .hdoivent être inclus par chaque fichier qui l'utilise.

Brendan Long
la source
6
C'est vrai, mais le #ifndef _CALLBACK_H_, en plus, n'empêche pas le compilateur de le traiter plusieurs fois?
hytromo
11
@ user9379 Cela l'empêchera d'être inclus plus d'une fois par fichier .c ou .cpp. Chaque fichier .c ou .cpp est généralement construit individuellement, ce qui signifie qu'un .h sera ré-analysé pour chaque fichier .c ou .cpp que vous compilez.
Brendan Long
2
Je pense que la principale raison d'en mettre le moins possible dans le .hest d'éviter dans certains cas une erreur due à une boucle d'inclusion. Exemple: deux classes ont besoin l'une de l'autre pour leurs implémentations, mais pas pour leurs déclarations. Mettre les deux inclus dans le .cpps évitera une erreur.
Codoscope
1
@ Qu'est-cet'yont C'est une raison pour laquelle vous ne pouvez pas mettre certaines choses dans les fichiers .h. Cette réponse explique pourquoi vous devriez mettre encore moins que cela.
Brendan Long le
@BrendanLong je vois, bien que dans mon sens, inclure plusieurs fois un même en-tête n'a pas d'importance si vous mettez les bonnes macros à l'intérieur pour inclure le contenu une seule fois. Par conséquent, je pense que mettre encore moins, c'est réduire les probabilités d'obtenir une erreur dans le futur avec des modifications du code.
Codoscope
55

Le seul moment où vous devez inclure un en-tête dans un autre fichier .h est si vous devez accéder à une définition de type dans cet en-tête; par exemple:

#ifndef MY_HEADER_H
#define MY_HEADER_H

#include <stdio.h>

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

#endif

Si l'en-tête A dépend de l'en-tête B tel que l'exemple ci-dessus, alors l'en-tête A doit inclure l'en-tête B directement. N'essayez PAS de classer vos inclusions dans le fichier .c pour satisfaire les dépendances (c'est-à-dire, y compris l'en-tête B avant l'en-tête A); c'est un gros tas de brûlures d'estomac qui attendent de se produire. Je suis sérieux. J'ai été dans ce film plusieurs fois et ça s'est toujours terminé avec Tokyo en flammes.

Oui, cela peut entraîner des fichiers inclus plusieurs fois, mais s'ils ont des protections d'inclusion appropriées configurées pour se protéger contre plusieurs erreurs de déclaration / définition, alors quelques secondes supplémentaires de temps de construction ne valent pas la peine de s'inquiéter. Essayer de gérer manuellement les dépendances est une douleur dans le cul.

Bien sûr, vous ne devriez pas inclure de fichiers là où vous n'en avez pas besoin .

John Bode
la source
10

Mettez autant d'includes que possible dans votre cpp et uniquement celles qui sont nécessaires au fichier hpp dans le fichier hpp. Je pense que cela aidera à accélérer la compilation, car les fichiers hpp seront moins référencés.

Pensez également à utiliser des déclarations directes dans votre fichier hpp pour réduire davantage la chaîne de dépendances d'inclusion.

Parappa
la source
1
Oo. La chose des déclarations anticipées est intéressante.
Brendan Long
Parappa, les déclarations prospectives sont très utiles dans les scénarios de référence circulaire. Mais seraient-ils une bonne pratique dans d'autres scénarios? (Je suis nouveau en C ++, donc je demande honnêtement)
Dzyann
5

Si je #include <callback.h>, je ne veux pas avoir à #includebeaucoup d'autres fichiers d'en-tête pour obtenir mon code à compiler. En callback.hvous devriez inclure tout le nécessaire pour compiler contre. Mais rien de plus.

Déterminez si l'utilisation de déclarations directes dans votre fichier d'en-tête (comme class GtkButton;) suffira, vous permettant de réduire le nombre de #includedirectives dans l'en-tête (et, par conséquent, mon temps de compilation et ma complexité).

Johnsyweb
la source
Je ne suis pas d'accord. Inclure le monde entier dans les fichiers H augmente la chaîne de dépendance et donc les temps de compilation.
John Dibling
Ma réponse ne recommandait pas d'inclure le monde entier dans le fichier d'en-tête, j'ai suggéré d'en inclure juste assez pour que l'utilisateur de l'API n'ait pas à passer du temps à rechercher des dépendances.
Johnsyweb