Soll ich die Includes in die Header-Datei oder die Quelldatei einfügen? Wenn die Header-Datei die include-Anweisungen enthält, wenn ich diese Header-Datei in meine Quelle einbinde, enthält meine Quelldatei dann alle enthaltenen Dateien, die sich in meinem Header befanden? Oder sollte ich sie nur in meine Quelldatei aufnehmen?
106
Antworten:
Fügen Sie Includes nur dann in einen Header ein, wenn der Header sie selbst benötigt.
Beispiele:
size_t
. Dann#include <stddef.h>
in der Header- Datei.strlen
. Dann#include <string.h>
in der Quelldatei .quelle
size_t
akzeptiert?size_t
oder hatstd::string
?Im Laufe der Jahre gab es einige Meinungsverschiedenheiten darüber. Zu einer Zeit war es traditionell so, dass ein Header nur deklarierte, in welchem Modul er sich befand. So viele Header hatten bestimmte Anforderungen, dass Sie
#include
einen bestimmten Satz von Headern (in einer bestimmten Reihenfolge) haben. Einige extrem traditionelle C-Programmierer folgen immer noch diesem Modell (zumindest in einigen Fällen religiös).In jüngerer Zeit gibt es eine Tendenz, die meisten Header eigenständig zu machen. Wenn dieser Header etwas anderes erfordert, übernimmt der Header selbst dies und stellt sicher, dass alles, was er benötigt, enthalten ist (in der richtigen Reihenfolge, wenn es Bestellprobleme gibt). Persönlich bevorzuge ich dies - besonders wenn die Reihenfolge der Überschriften wichtig sein kann, löst es das Problem einmal, anstatt dass jeder, der es verwendet, das Problem noch einmal lösen muss.
Beachten Sie, dass die meisten Header nur Deklarationen enthalten sollten. Dies bedeutet, dass das Hinzufügen eines unnötigen Headers (normalerweise) keine Auswirkungen auf Ihre endgültige ausführbare Datei haben sollte. Das Schlimmste, was passiert, ist, dass es die Kompilierung etwas verlangsamt.
quelle
Ihr
#include
s sollte aus Header-Dateien bestehen, und jede Datei (Quelle oder Header) sollte#include
die Header-Dateien enthalten, die sie benötigt. Header-Dateien sollten#include
die minimal erforderlichen Header-Dateien enthalten, und Quelldateien sollten dies auch tun, obwohl dies für Quelldateien nicht so wichtig ist.Die Quelldatei enthält die Header
#include
und die Header#include
usw. bis zur maximalen Verschachtelungstiefe. Aus diesem Grund möchten Sie keine überflüssigen#include
s in Header-Dateien: Sie können dazu führen, dass eine Quelldatei viele Header-Dateien enthält, die möglicherweise nicht benötigt werden, was die Kompilierung verlangsamt.Dies bedeutet, dass es durchaus möglich ist, dass Header-Dateien zweimal enthalten sind, und das kann ein Problem sein. Die traditionelle Methode besteht darin, "Include Guards" in Header-Dateien einzufügen, z. B. für die Datei foo.h:
quelle
Der Ansatz, zu dem ich mich in über zwanzig Jahren entwickelt habe, ist dieser;
Betrachten Sie eine Bibliothek.
Es gibt mehrere C-Dateien, eine interne H-Datei und eine externe H-Datei. Die C-Dateien enthalten die interne H-Datei. Die interne H-Datei enthält die externe H-Datei.
Sie sehen, dass aus dem POV des Compilers beim Kompilieren einer C-Datei eine Hierarchie besteht.
extern -> intern -> C-Code
Dies ist die richtige Reihenfolge, da das, was extern ist, alles ist, was ein Dritter benötigt, um die Bibliothek zu nutzen. Das Interne ist erforderlich, um den C-Code zu kompilieren.
quelle
Wenn Header - Datei Eine
#includes
Header - Dateien B und C, so ist jede Quelldatei , dass#includes
A auch B und C erhalten#included
. Der Vorprozessor führt buchstäblich nur eine Textersetzung durch: überall dort, wo er Text findet, der besagt,#include <foo.h>
dass er durch den Text derfoo.h
Datei ersetzt wird.Es gibt unterschiedliche Meinungen darüber, ob Sie
#includes
Header oder Quelldateien einfügen sollten. Persönlich ziehe ich es vor, alle#includes
standardmäßig in die Quelldatei aufzunehmen, aber alle Header-Dateien, die ohne andere vorausgesetzte Header nicht kompiliert werden können, sollten#include
diese Header selbst verwenden.Und jede Header-Datei sollte einen Include-Guard enthalten, um zu verhindern, dass sie mehrmals eingeschlossen wird.
quelle
In einigen Umgebungen ist die Kompilierung am schnellsten, wenn nur die benötigten Header-Dateien enthalten sind. In anderen Umgebungen wird die Kompilierung optimiert, wenn alle Quelldateien dieselbe primäre Sammlung von Headern verwenden können (einige Dateien enthalten möglicherweise zusätzliche Header, die über die gemeinsame Teilmenge hinausgehen). Im Idealfall sollten Header so erstellt werden, dass mehrere # include-Operationen keine Auswirkung haben. Es kann sinnvoll sein, # include-Anweisungen mit Überprüfungen des Include-Schutzes der einzuschließenden Datei zu umgeben, obwohl dies eine Abhängigkeit vom Format dieses Schutzes schafft. Abhängig vom Dateicaching-Verhalten eines Systems kann es außerdem nicht lange dauern, bis ein unnötiger # Include, dessen Ziel am Ende vollständig # ifdef'ed ist, entfernt wird.
Eine andere zu berücksichtigende Sache ist, dass, wenn eine Funktion einen Zeiger auf eine Struktur nimmt, man den Prototyp als schreiben kann
ohne dass eine Definition für BAR_s im Gültigkeitsbereich liegen muss. Ein sehr praktischer Ansatz zur Vermeidung unnötiger Einschlüsse.
PS: In vielen meiner Projekte wird es eine Datei geben, von der erwartet wird, dass jedes Modul #include enthält, die Dinge wie typedefs für ganzzahlige Größen und einige gemeinsame Strukturen und Vereinigungen enthält [z
(Ja, ich weiß, dass ich in Schwierigkeiten geraten würde, wenn ich zu einer Big-Endian-Architektur wechseln würde. Da mein Compiler jedoch keine anonymen Strukturen in Unions zulässt, muss für die Verwendung benannter Bezeichner für die Bytes innerhalb der Union auf sie zugegriffen werden theUnion.b.b1 usw., was ziemlich nervig erscheint.
quelle
Erstellen Sie alle Ihre Dateien so, dass sie nur mit dem erstellt werden können, was sie enthalten. Wenn Sie kein Include in Ihrem Header benötigen, entfernen Sie es. Wenn Sie in einem großen Projekt diese Disziplin nicht beibehalten, können Sie einen gesamten Build brechen, wenn jemand ein Include aus einer Header-Datei entfernt, die von einem Konsumenten dieser Datei und nicht einmal vom Header verwendet wird.
quelle
Ihre Quelldatei enthält die include-Anweisungen, wenn Sie sie in den Header einfügen. In einigen Fällen ist es jedoch besser, sie in die Quelldatei einzufügen.
Denken Sie daran, dass, wenn Sie diesen Header in andere Quellen aufnehmen, diese auch die Includes aus dem Header erhalten, was nicht immer wünschenswert ist. Sie sollten nur Dinge einschließen, in denen sie verwendet werden.
quelle
Sie sollten nur Dateien in Ihren Header aufnehmen, die Sie zum Deklarieren von Konstanten und Funktionsdeklarationen benötigen. Technisch gesehen sind diese Includes auch in Ihrer Quelldatei enthalten. Aus Gründen der Übersichtlichkeit sollten Sie jedoch nur die Dateien in jede Datei aufnehmen, die Sie tatsächlich verwenden müssen. Sie sollten sie auch in Ihrem Header vor mehrfacher Aufnahme schützen:
Dies verhindert, dass der Header mehrmals eingeschlossen wird, was zu einem Compilerfehler führt.
quelle