web-dev-qa-db-fra.com

Qu'est-ce qui devrait et ne devrait pas être dans un fichier d'en-tête?

Quelles choses ne doivent absolument jamais être incluses dans un fichier d'en-tête?

Si, par exemple, je travaille avec un format standard de l'industrie documenté qui a beaucoup de constantes, est-ce une bonne pratique de les définir dans un fichier d'en-tête (si j'écris un analyseur pour ce format)?

Quelles fonctions doivent aller dans le fichier d'en-tête?
Quelles fonctions ne devraient pas?

75
Moshe Magnes

Que mettre dans les en-têtes:

  • L'ensemble minimal de directives #include Nécessaires pour rendre l'en-tête compilable lorsque l'en-tête est inclus dans un fichier source.
  • Définitions de symboles de préprocesseur des choses qui doivent être partagées et qui ne peuvent être accomplies que via le préprocesseur. Même en C, les symboles du préprocesseur doivent être réduits au minimum.
  • Transférer les déclarations de structures nécessaires pour rendre les définitions de structure, les prototypes de fonctions et les déclarations de variables globales dans le corps de l'en-tête compilables.
  • Définitions des structures de données et des énumérations partagées entre plusieurs fichiers source.
  • Déclarations de fonctions et de variables dont les définitions seront visibles par l'éditeur de liens.
  • Définissez les fonctions en ligne, mais faites attention ici.

Ce qui n'appartient pas à un en-tête:

  • Directives gratuites #include. Ces gratifications incluent la recompilation de choses qui n'ont pas besoin d'être recompilées, et peuvent parfois faire en sorte qu'un système ne puisse pas compiler. Ne pas #include Un fichier dans un en-tête si l'en-tête lui-même n'a pas besoin de cet autre fichier d'en-tête.
  • Symboles du préprocesseur dont l'intention pourrait être accomplie par un mécanisme, un mécanisme autre que le préprocesseur.
  • Beaucoup, beaucoup de définitions de structure. Divisez-les en en-têtes séparés.
  • Définitions en ligne des fonctions qui nécessitent un #include Supplémentaire, qui sont susceptibles de changer ou qui sont trop grandes. Ces fonctions en ligne devraient avoir peu ou pas de fan out, et si elles ont un fan out, elles devraient être localisées dans les éléments définis dans l'en-tête.

Qu'est-ce qui constitue l'ensemble minimal d'instructions #include?

Il s’agit là d’une question non triviale. Une définition TL; DR: un fichier d'en-tête doit inclure les fichiers d'en-tête qui définissent directement chacun des types directement utilisés dans ou qui déclarent directement chacune des fonctions utilisées dans le fichier d'en-tête en question, mais ne doit rien inclure d'autre. Un pointeur ou un type de référence C++ n'est pas considéré comme une utilisation directe; les références directes sont préférées.

Il y a une place pour une directive #include Gratuite, et c'est dans un test automatisé. Pour chaque fichier d'en-tête dans un progiciel, je génère et compile automatiquement les éléments suivants:

#include "path/to/random/header_under_test"
int main () { return 0; }

La compilation doit être propre (c'est-à-dire exempte d'avertissements ou d'erreurs). Des avertissements ou des erreurs concernant des types incomplets ou des types inconnus signifient que le fichier d'en-tête sous test contient des directives #include Manquantes et/ou des déclarations aval manquantes. Notez bien: ce n'est pas parce que le test réussit que l'ensemble des directives #include Est suffisant, et encore moins minimal.

60
David Hammen

En plus de ce qui a déjà été dit.

Les fichiers H doivent toujours contenir:

  • Documentation du code source !!! Au minimum, à quoi servent les différents paramètres et valeurs de retour des fonctions.
  • Protecteurs d'en-tête, #ifndef MYHEADER_H #define MYHEADER_H ... #endif

Les fichiers H ne doivent jamais contenir:

  • Toute forme d'allocation de données.
  • Définitions des fonctions. Les fonctions en ligne peuvent être une exception rare dans certains cas.
  • Tout ce qui est étiqueté static.
  • Typedefs, #defines ou constantes qui n'ont aucune pertinence pour le reste de l'application.

(Je dirais également qu'il n'y a jamais aucune raison d'utiliser des variables globales/externes non constantes, n'importe où, mais c'est une discussion pour un autre article.)

16
user29079

Le fichier d'en-tête doit avoir l'organisation suivante:

  • type et définitions constantes
  • déclarations d'objets externes
  • déclarations de fonctions externes

Les fichiers d'en-tête ne doivent jamais contenir de définitions d'objet, uniquement des définitions de type et des déclarations d'objet.

4
theD

Je ne dirais probablement jamais jamais, mais les instructions qui génèrent des données et du code au fur et à mesure de leur analyse ne devraient pas figurer dans un fichier .h.

Les macros, les fonctions en ligne et les modèles peuvent ressembler à des données ou du code, mais ils ne génèrent pas de code au fur et à mesure de leur analyse, mais plutôt lorsqu'ils sont utilisés. Ces éléments doivent souvent être utilisés dans plusieurs .c ou .cpp, ils appartiennent donc au .h.

À mon avis, un fichier d'en-tête devrait avoir l'interface pratique minimale à un .c ou .cpp correspondant. L'interface peut inclure #defines, class, typedef, des définitions de structure, des prototypes de fonction et des définitions externes moins préférées pour les variables globales. Cependant, si une déclaration est utilisée dans un seul fichier source, elle doit probablement être exclue du fichier .h et contenue dans le fichier source à la place.

Certains peuvent être en désaccord, mais mes critères personnels pour les fichiers .h sont qu'ils #incluent tous les autres fichiers .h dont ils ont besoin pour pouvoir compiler. Dans certains cas, cela peut être beaucoup de fichiers, nous avons donc des méthodes efficaces pour réduire les dépendances externes comme les déclarations directes aux classes qui nous permettent d'utiliser des pointeurs vers les objets d'une classe sans inclure ce qui pourrait être une grande arborescence de fichiers d'inclusion.

4
DeveloperDon

Les instructions qui génèrent des données et du code lors de leur analyse ne doivent pas être dans un .h fichier. En ce qui concerne mon point de vue, un fichier d'en-tête ne devrait avoir que l'interface pratique minimale vers un .c ou .cpp.

0
Ajay Prasad