programming C/C++ enthält Dateireihenfolge/Best Practices




c++ programming (8)

Gibt es eine empfohlene Reihenfolge, in der Include-Dateien angegeben werden sollten?

Gehen beispielsweise die Systemdateien, STL und Boost vor oder nach den lokalen Include-Dateien?

Gibt es einen besonderen Grund, sich für das eine oder andere zu entscheiden? Ich nehme an, Include-Dateien haben die richtigen Abhängigkeiten angegeben.


Ich denke nicht, dass es eine empfohlene Reihenfolge gibt, solange es kompiliert wird! Was nervig ist, ist, wenn einige Header erfordern, dass andere Header zuerst eingefügt werden ... Das ist ein Problem mit den Headern selbst, nicht mit der Reihenfolge der Includes.

Meine persönliche Präferenz ist es, von lokal nach global zu gehen, jede Untersektion in alphabetischer Reihenfolge, dh:

  1. h-Datei, die dieser cpp-Datei entspricht (falls zutreffend)
  2. Header aus der gleichen Komponente,
  3. Header von anderen Komponenten,
  4. System-Header.

Mein Grundgedanke für 1. ist, dass es beweisen sollte, dass jeder Header (für den es eine cpp gibt) #include ohne Voraussetzungen enthalten sein kann. Und der Rest scheint nur logisch von dort zu fließen.


Ich folge zwei einfachen Regeln, die die große Mehrheit der Probleme vermeiden:

  1. Alle Header (und in der Tat alle Quelldateien) sollten enthalten, was sie brauchen. Sie sollten sich nicht darauf verlassen, dass ihre Benutzer Dinge enthalten.
  2. Zusätzlich sollten alle Header Wächter enthalten, so dass sie nicht mehrfach durch übertriebene Anwendung der obigen Regel 1 einbezogen werden.

Ich folge auch den Richtlinien von:

  1. Fügen Sie zuerst die System-Header (stdio.h usw.) mit einer Trennlinie ein.
  2. Gruppiere sie logisch.

Mit anderen Worten:

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

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

Obwohl das eine Richtlinie ist, ist das eine subjektive Sache. Die Regeln auf der anderen Seite, die ich streng durchsetze, sogar bis zu dem Punkt der Bereitstellung von 'Wrapper' Header-Dateien mit Include-Wachen und gruppierte enthält, wenn einige widerliche Drittanbieter-Entwickler nicht meine Vision abonniert :-)


Es ist eine schwierige Frage in der C / C ++ - Welt mit so vielen Elementen jenseits des Standards.

Ich denke, Header-Datei-Reihenfolge ist kein ernstes Problem, solange es kompiliert, wie Squelart sagte.

Meine Ideen sind: Wenn es keinen Konflikt von Symbolen in allen diesen Headern gibt, ist jede Reihenfolge in Ordnung, und das Headerabhängigkeitsproblem kann später durch Hinzufügen von #include-Zeilen zu dem fehlerhaften .h behoben werden.

Der wirkliche Ärger entsteht, wenn einige Header ihre Aktion ändern (indem sie #if Bedingungen überprüfen), je nachdem, welche Header oben sind.

Zum Beispiel gibt es in stddef.h in VS2005:

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

Jetzt das Problem: Wenn ich einen benutzerdefinierten Header ("custom.h") habe, der mit vielen Compilern verwendet werden muss, einschließlich einiger älterer, die offsetof in ihren offsetof nicht bereitstellen, sollte ich in meine Kopfzeile schreiben:

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

Und vergewissern Sie sich, dass der Benutzer nach allen #include "custom.h" , andernfalls wird die Zeile von offsetof in stddef.h einen offsetof bestätigen.

Wir beten, dass wir in unserer Karriere keine weiteren derartigen Fälle mehr sehen.


Ich bin mir ziemlich sicher, dass dies keine empfohlene Praxis irgendwo in der gesunden Welt ist, aber ich mag Line-System umfasst bis Dateinamenlänge, lexikalisch innerhalb der gleichen Länge sortiert. Wie so:

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

Ich denke, es ist eine gute Idee, Ihre eigenen Kopfzeilen vor anderen Leuten einzubauen, um die Schande der Abhängigkeit von der Einschlussreihenfolge zu vermeiden.


Fügen Sie vom spezifischsten zum am wenigsten spezifischen hinzu, beginnend mit der entsprechenden .hpp-Datei für die .cpp-Datei, falls eine solche existiert. Auf diese Weise werden alle versteckten Abhängigkeiten in Header-Dateien aufgedeckt, die nicht autark sind.

Dies wird durch die Verwendung von vorkompilierten Headern kompliziert. Eine Möglichkeit ist, ohne dass Ihr Projekt compilerspezifisch ist, einen der Projektheader als vorkompilierte Header-Include-Datei zu verwenden.


Um meinen eigenen Stein an die Wand zu bringen.

  1. Jeder Header muss autark sein, was nur getestet werden kann, wenn er mindestens einmal enthalten ist
  2. Man sollte nicht fälschlicherweise die Bedeutung eines Headers eines Drittanbieters ändern, indem man Symbole (Makros, Typen usw.) einführt.

Also gehe ich normalerweise so:

// 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"

Jede Gruppe wird durch eine Leerzeile vom nächsten getrennt:

  • Kopfzeile, die dieser CPP-Datei entspricht (Plausibilitätsprüfung)
  • Systemkopfzeilen
  • Header von Drittanbietern, geordnet nach Abhängigkeitsreihenfolge
  • Projektheader
  • Projekt private Header

Beachten Sie außerdem, dass sich jede Datei abgesehen von Systemheadern in einem Ordner mit dem Namen ihres Namespace befindet, nur weil es einfacher ist, sie auf diese Weise zu verfolgen.


Das ist nicht subjektiv. Stellen Sie sicher, dass Ihre Header nicht darauf angewiesen sind, dass #include d in einer bestimmten Reihenfolge enthalten ist. Sie können sicher sein, dass es egal ist, in welcher Reihenfolge Sie STL- oder Boost-Header einfügen.


Das Wichtigste ist, dass Ihre Header nicht davon abhängig sein sollten, dass andere Header zuerst eingefügt werden. Eine Möglichkeit, dies zu gewährleisten, besteht darin, die Header vor allen anderen Headern einzufügen.

"Thinking in C ++" erwähnt dies insbesondere und bezieht sich auf Lakos "Large Scale C ++ Software Design":

Latente Verwendungsfehler können vermieden werden, indem sichergestellt wird, dass die .h-Datei einer Komponente selbst analysiert - ohne von außen bereitgestellte Deklarationen oder Definitionen ... Durch die Aufnahme der .h-Datei als allererste Zeile der .c-Datei wird sichergestellt, dass keine kritische Komponente vorhanden ist Informationen, die der physischen Schnittstelle der Komponente innewohnen, fehlen in der .h-Datei (oder, falls vorhanden, dass Sie davon erfahren werden, sobald Sie versuchen, die .c-Datei zu kompilieren).

Das heißt, in der folgenden Reihenfolge einschließen:

  1. Der Prototyp / Interface-Header für diese Implementierung (dh die .h / .hh-Datei, die dieser .cpp / .cc-Datei entspricht).
  2. Andere Header aus dem gleichen Projekt, je nach Bedarf.
  3. Header aus anderen Nicht-Standardbibliotheken (z. B. Qt, Eigen usw.).
  4. Header aus anderen "fast-Standard" -Bibliotheken (zum Beispiel Boost)
  5. Standard-C ++ - Header (z. B. iostream, funktional usw.)
  6. Standard-C-Header (z. B. cstdint, dirent.h usw.)

Wenn einer der Header ein Problem mit der Aufnahme in diese Reihenfolge hat, beheben Sie sie entweder (falls Sie Ihre sind) oder verwenden Sie sie nicht. Boykott-Bibliotheken, die keine sauberen Header schreiben.

Googles C ++ Style Guide argumentiert fast das Gegenteil, mit wirklich überhaupt keinen Rechtfertigungen; Ich persönlich bevorzuge den Ansatz von Lakos.





c