web-dev-qa-db-fra.com

Ordre des fichiers d'en-tête d'inclusion C / C ++

Quel ordre faut-il spécifier pour inclure les fichiers, c’est-à-dire quelles sont les raisons pour inclure un en-tête avant un autre?

Par exemple, les fichiers système, STL et Boost vont-ils avant ou après les fichiers d'inclusion locaux?

254
Anycorn

Je ne pense pas qu'il y ait un ordre recommandé, tant qu'il compile! Ce qui est embêtant, c’est que certains en-têtes nécessitent d’inclure d’abord les en-têtes… C’est un problème avec les en-têtes eux-mêmes, et non avec l’ordre des inclus.

Ma préférence personnelle est d’aller du local au global, chaque sous-titre par ordre alphabétique, c’est-à-dire:

  1. fichier h correspondant à ce fichier cpp (le cas échéant)
  2. en-têtes du même composant,
  3. en-têtes d'autres composants,
  4. en-têtes de système.

Mon raisonnement pour 1. est qu'il doit prouver que chaque en-tête (pour lequel il y a un cpp) peut être #included sans conditions préalables. Et le reste semble découler logiquement de là.

262
squelart

Il est important de garder à l'esprit que vos en-têtes ne doivent pas dépendre d'autres en-têtes. Une façon de s’assurer que c’est d’inclure vos en-têtes avant tout autre en-tête.

"Thinking in C++" en particulier le mentionne, en faisant référence à la "conception de logiciel C++ à grande échelle" de Lakos:

Les erreurs d'utilisation latentes peuvent être évitées en veillant à ce que le fichier .h d'un composant soit analysé lui-même - sans déclarations ni définitions fournies en externe ... L'inclusion du fichier .h dans la toute première ligne du fichier .c garantit qu'aucune pièce essentielle ne soit critique. Il manque des informations intrinsèques à l'interface physique du composant dans le fichier .h (ou, le cas échéant, vous le saurez dès que vous essayez de compiler le fichier .c).

C'est-à-dire, incluez dans l'ordre suivant:

  1. En-tête prototype/interface de cette implémentation (c'est-à-dire, le fichier .h/.hh qui correspond à ce fichier .cpp/.cc).
  2. Autres en-têtes du même projet, si nécessaire.
  3. En-têtes d'autres bibliothèques non standard et non système (par exemple, Qt, Eigen, etc.).
  4. En-têtes d'autres bibliothèques "presque standard" (par exemple, Boost)
  5. En-têtes C++ standard (par exemple, iostream, fonctionnel, etc.)
  6. En-têtes standard C (par exemple, cstdint, dirent.h, etc.)

Si l'un des en-têtes a un problème avec l'inclusion dans cette commande, corrigez-le (si le vôtre) ou ne l'utilisez pas. Boycott des bibliothèques qui n'écrivent pas des en-têtes propres.

Guide de style C++ de Google argumente presque l'inverse, sans aucune justification du tout; Personnellement, j'ai tendance à privilégier l'approche des Lakos.

89
Nathan Paul Simons

Je suis deux règles simples qui évitent la grande majorité des problèmes:

  1. Tous les en-têtes (et en effet tous fichiers source) doivent inclure ce dont ils ont besoin. Ils devraient pas compter sur leurs utilisateurs, y compris les choses.
  2. En tant que complément, tous les en-têtes devraient inclure des gardes afin qu'ils ne soient pas inclus plusieurs fois par une application trop ambitieuse de la règle 1 ci-dessus.

Je suis aussi les directives de:

  1. Incluez d’abord les en-têtes système (stdio.h, etc.) avec une ligne de séparation.
  2. Regroupez-les logiquement.

En d'autres termes:

#include <stdio.h>
#include <string.h>

#include "btree.h"
#include "collect_hash.h"
#include "collect_arraylist.h"
#include "globals.h"

Bien que, étant des lignes directrices, c'est une chose subjective. Les règles d’autre part, j’applique de manière rigide, au point même de fournir des fichiers d’entêtes 'wrapper' avec des gardes include et des include groupées si un développeur tiers odieux ne souscrit pas à ma vision :-)

48
paxdiablo

Pour ajouter ma propre brique au mur.

  1. Chaque en-tête doit être autonome, ce qui ne peut être testé que s'il est inclus au moins une fois
  2. Il ne faut pas modifier par erreur la signification d'un en-tête tiers en introduisant des symboles (macro, types, etc.)

Donc je vais généralement comme ça:

// myproject/src/example.cpp
#include "myproject/example.h"

#include <algorithm>
#include <set>
#include <vector>

#include <3rdparty/foo.h>
#include <3rdparty/bar.h>

#include "myproject/another.h"
#include "myproject/specific/bla.h"

#include "detail/impl.h"

Chaque groupe séparé par une ligne vierge de la suivante:

  • En-tête correspondant à ce fichier cpp en premier (vérification de l'intégrité)
  • En-têtes de système
  • En-têtes de tiers, organisés par ordre de dépendance
  • En-têtes de projet
  • En-têtes privés du projet

Notez également que, mis à part les en-têtes système, chaque fichier se trouve dans un dossier portant le nom de son espace de noms, simplement parce qu'il est plus facile de les rechercher de cette façon.

21
Matthieu M.

Je suis presque sûr que ce n'est pas une pratique recommandée dans le monde sain d'esprit, mais j'aime bien aligner le système en fonction de la longueur du nom de fichier, trié lexicalement dans la même longueur. Ainsi:

#include <set>
#include <vector>
#include <algorithm>
#include <functional>

Je pense que c'est une bonne idée d'inclure vos propres en-têtes avant les autres peuples, pour éviter la honte de la dépendance par ordre d'inclusion.

15
msandiford

Je recommande:

  1. En-tête du module .cc que vous construisez. (Cela permet de s’assurer que chaque en-tête de votre projet n’a pas de dépendance implicite par rapport aux autres en-têtes de votre projet.)
  2. C fichiers système.
  3. Fichiers système C++.
  4. Fichiers d'en-tête Platform/OS/other (par exemple, win32, gtk, openGL).
  5. Autres fichiers d'en-tête de votre projet.

Et bien sûr, ordre alphabétique dans chaque section, si possible.

Utilisez toujours des déclarations anticipées pour éviter les #includes inutiles dans vos fichiers d’en-tête.

14
i_am_jorf

Ce n'est pas subjectif. Assurez-vous que vos en-têtes ne reposent pas sur le fait d'être #included dans un ordre spécifique. Vous pouvez être sûr que l'ordre dans lequel vous incluez les en-têtes STL ou Boost importe peu.

6
wilhelmtell

Commencez par inclure l'en-tête correspondant au fichier .cpp ... en d'autres termes, source1.cpp doit inclure source1.h avant d'inclure quoi que ce soit d'autre. La seule exception à laquelle je peux penser est lorsque vous utilisez MSVC avec des en-têtes pré-compilés, auquel cas vous êtes obligé d'inclure stdafx.h avant toute autre chose.

Reasoning: Inclure le source1.h avant tout autre fichier garantit qu'il peut être autonome sans ses dépendances. Si source1.h prend une dépendance à une date ultérieure, le compilateur vous avertira immédiatement d'ajouter les déclarations de transfert requises à source1.h. Cela garantit que les en-têtes peuvent être inclus dans n'importe quel ordre par leurs personnes à charge.

Exemple:

source1.h

class Class1 {
    Class2 c2;    // a dependency which has not been forward declared
};

source1.cpp

#include "source1.h"    // now compiler will alert you saying that Class2 is undefined
                    // so you can forward declare Class2 within source1.h
...

tilisateurs de MSVC: Je recommande fortement d'utiliser des en-têtes pré-compilés. Donc, déplacez toutes les directives #include pour les en-têtes standard (et les autres en-têtes qui ne changeront jamais) vers stdafx.h.

3
Agnel Kurian

Incluez du plus spécifique au moins spécifique, en commençant par le .hpp correspondant au .cpp, s'il en existe un. De cette façon, toutes les dépendances cachées dans les fichiers d'en-tête qui ne sont pas autosuffisantes seront révélées.

Ceci est compliqué par l'utilisation d'en-têtes pré-compilés. Une solution consiste à utiliser l'un des en-têtes de projet comme fichier d'inclusion d'en-tête précompilé, sans que votre projet ne soit spécifique au compilateur.

2
dcw

C’est une question difficile dans le monde du C/C++, avec tant d’éléments dépassant la norme.

Je pense que l'ordre des fichiers d'en-tête n'est pas un problème grave tant qu'il compile, comme dit squelart.

Mon idée est la suivante: s'il n'y a pas de conflit de symboles dans tous ces en-têtes, tout ordre est correct et le problème de dépendance d'en-tête peut être résolu ultérieurement en ajoutant des lignes #include au fichier défectueux .h.

Le véritable problème survient lorsque certains en-têtes modifient leur action (en vérifiant #if conditions) en fonction des en-têtes ci-dessus.

Par exemple, dans stddef.h dans VS2005, il y a:

#ifdef  _WIN64
#define offsetof(s,m)   (size_t)( (ptrdiff_t)&(((s *)0)->m) )
#else
#define offsetof(s,m)   (size_t)&(((s *)0)->m)
#endif

Maintenant, le problème: si j’ai un en-tête personnalisé ("custom.h") qui doit être utilisé avec de nombreux compilateurs, y compris certains anciens qui ne fournissent pas offsetof dans leurs en-têtes système, j’écrirai dans mon entête:

#ifndef offsetof
#define offsetof(s,m)   (size_t)&(((s *)0)->m)
#endif

Et assurez-vous de dire à l'utilisateur de #include "custom.h"after tous les en-têtes système, sinon la ligne de offsetof dans stddef.h affirmera une erreur de redéfinition des macros.

Nous prions pour que de tels cas ne se rencontrent plus dans notre carrière.

0
Jimm Chen