Wo sollen Include-Anweisungen, Header oder Quelle platziert werden?

Lesezeit: 6 Minuten

Benutzeravatar von Mohit Deshpande
Mohit Deshpande

Soll ich die Includes in die Header-Datei oder in die Quelldatei einfügen? Wenn die Header-Datei die Include-Anweisungen enthält und ich diese Header-Datei dann in meinen Quellcode einfüge, enthält meine Quelldatei dann alle enthaltenen Dateien, die in meinem Header enthalten waren? Oder sollte ich sie nur in meine Quelldatei aufnehmen?

  • Viele frühere Duplikate auf SO, z. B. wo sollte “include” in C++ eingefügt werden

    – PaulR

    15. Oktober 2010 um 15:09 Uhr


  • mögliches Duplikat von Soll ich #include in Headern verwenden?

    – schott

    15. Oktober 2010 um 15:17 Uhr

schots Benutzeravatar
schott

Fügen Sie Includes nur dann in einen Header ein, wenn der Header selbst sie benötigt.

Beispiele:

  • Ihre Funktion gibt Typ zurück size_t. Dann #include <stddef.h> in dem Header Datei.
  • Ihre Funktion verwendet strlen. Dann #include <string.h> in dem Quelle Datei.

  • Was ist, wenn meine Funktion ein Argument vom Typ akzeptiert? size_t?

    – andrybak

    15. November 2013 um 13:27 Uhr

  • Dieselbe Frage erweitert auf c++: Was ist, wenn meine Struktur/Klasse ein Feld/Member vom Typ hat? size_t oder std::string?

    – andrybak

    15. November 2013 um 13:32 Uhr


  • Was ist die Begründung?

    – Patrizio Bertoni

    15. Januar 2016 um 12:51 Uhr

  • Ich habe eine verdrahtete Situation, die C++-Klasse A hat ein Objekt einer anderen Klasse B, und ich kann die Vorwärtsdeklaration von B und das Ende einschließlich des B-Headers innerhalb des A-Headers nicht verwenden. (Die Verwendung des Zeigers hat dieses Problem nicht)

    – KRoy

    30. August 2017 um 14:49 Uhr

  • @andrybak Ihre Quelldateien sollten Ihre Header-Datei enthalten, damit alle Einschlüsse, die Ihr Header enthält, auch Ihre Quelle erhalten.

    – Jeremy Trifilo

    9. Januar 2019 um 3:14 Uhr


Darüber gab es im Laufe der Jahre einige Meinungsverschiedenheiten. Früher war es Tradition, dass ein Kopfball nur Deklarieren Sie, was in dem Modul war, auf das es sich bezieht, also viele Kopfzeilen hatte spezifische Anforderungen, die Sie #include eine bestimmte Gruppe von Headern (in einer bestimmten Reihenfolge). Einige extrem traditionelle C-Programmierer folgen immer noch diesem Modell (religiös, zumindest in einigen Fällen).

In jüngerer Zeit gibt es eine Bewegung dahingehend, die meisten Header eigenständig zu machen. Wenn dieser Header etwas anderes erfordert, kümmert sich der Header selbst darum und stellt sicher, dass alles, was benötigt wird, enthalten ist (in der richtigen Reihenfolge, wenn es Probleme bei der Reihenfolge 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. Das 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.

  • Wenn alle Header im zweiten Stil geschrieben sind, sollte es überhaupt keine Sortierprobleme geben. Bestellprobleme in den Kopfzeilen bedeuten normalerweise, dass Sie nicht alles, was Sie brauchen, in die Kopfzeile aufgenommen haben.

    – Kami Kaze

    18. Juli 2019 um 14:14 Uhr

Dein #includes sollten Header-Dateien sein, und jede Datei (Quelle oder Header) sollte #include die benötigten Header-Dateien. Header-Dateien sollten #include die minimal erforderlichen Header-Dateien, und Quelldateien sollten dies auch tun, obwohl dies für Quelldateien nicht so wichtig ist.

Die Quelldatei enthält die Header it #includes, und die Überschriften sie #include, usw. bis zur maximalen Verschachtelungstiefe. Deshalb wollen Sie nichts Überflüssiges #includes in Header-Dateien: Sie können dazu führen, dass eine Quelldatei viele Header-Dateien enthält, die sie möglicherweise nicht benötigt, wodurch die Kompilierung verlangsamt wird.

Das bedeutet, dass es durchaus möglich ist, dass Header-Dateien doppelt eingebunden werden, was ein Problem darstellen kann. Die traditionelle Methode besteht darin, “Wächter einzuschließen” in Header-Dateien einzufügen, wie z. B. diese für die Datei foo.h:

#ifndef INCLUDE_FOO_H
#define INCLUDE_FOO_H
/* everything in header goes here */
#endif

  • Ich weiß, dass diese Antwort super alt ist, aber seitdem haben sie #pragma einmal hinzugefügt, also müssen Sie #ifndef nicht einschließen, wenn Sie #includes deklarieren

    – Dogunbound-Hunde

    13. Januar 2020 um 20:11 Uhr


Der Ansatz, zu dem ich mich in über zwanzig Jahren entwickelt habe, ist folgender;

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 es beim Compiler POV eine Hierarchie gibt, wenn er eine C-Datei kompiliert;

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 benutzen. Das, was intern ist, wird benötigt, um den C-Code zu kompilieren.

Wenn Header-Datei A #includes Header-Dateien B und C, dann jede Quelldatei, die #includes A bekommt auch B und C #included. Der Präprozessor führt buchstäblich nur eine Textersetzung durch: Überall dort, wo er Text findet, der sagt #include <foo.h> es ersetzt es durch den Text von foo.h Datei.

Es gibt unterschiedliche Meinungen darüber, ob Sie setzen sollten #includes in Headern oder Quelldateien. Ich persönlich ziehe es vor, alle zu setzen #includes standardmäßig in der Quelldatei, aber alle Header-Dateien, die nicht ohne andere erforderliche Header kompiliert werden können, sollten dies tun #include diese Header selbst.

Und jede Header-Datei sollte einen Include-Guard enthalten, um zu verhindern, dass sie mehrfach eingebunden wird.

Benutzeravatar von rerun
Wiederholung

Machen 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 diese Disziplin in einem großen Projekt nicht einhalten, riskieren Sie, einen ganzen Build zu beschädigen, wenn jemand ein Include aus einer Header-Datei entfernt, die von einem Verbraucher dieser Datei und nicht einmal vom Header verwendet wird.

Benutzeravatar von Supercat
Superkatze

In manchen Umgebungen geht die Kompilierung am schnellsten, wenn man nur die benötigten Header-Dateien einbindet. In anderen Umgebungen wird die Kompilierung optimiert, wenn alle Quelldateien dieselbe primäre Sammlung von Headern verwenden können (einige Dateien haben möglicherweise zusätzliche Header über die gemeinsame Teilmenge hinaus). Idealerweise sollten Header so konstruiert werden, dass mehrere #include-Operationen keine Auswirkung haben. Es kann sinnvoll sein, #include-Anweisungen mit Prüfungen für den include-guard der einzuschließenden Datei zu umgeben, obwohl dies eine Abhängigkeit vom Format dieses Guards erzeugt. Darüber hinaus kann es je nach Datei-Caching-Verhalten eines Systems nicht lange dauern, bis ein unnötiges #include, dessen Ziel vollständig #ifdef’ed ist, nicht lange dauert.

Eine andere zu berücksichtigende Sache ist, dass man den Prototyp schreiben kann, wenn eine Funktion einen Zeiger auf eine Struktur nimmt

void foo(struct BAR_s *bar);

ohne dass eine Definition für BAR_s im Geltungsbereich liegen muss. Ein sehr praktischer Ansatz, um unnötige Includes zu vermeiden.

PS–in vielen meiner Projekte wird es eine Datei geben, von der erwartet wird, dass jedes Modul #include wird, die Dinge wie Typedefs für Integer-Größen und ein paar gemeinsame Strukturen und Vereinigungen enthält[zB[eg

typedef union {
  unsigned long l;
  unsigned short lw[2];
  unsigned char lb[4];
} U_QUAD;

(Ja, ich weiß, dass ich in Schwierigkeiten geraten würde, wenn ich zu einer Big-Endian-Architektur wechseln würde, aber da mein Compiler keine anonymen Strukturen in Vereinigungen zulässt, würde die Verwendung von benannten Bezeichnern für die Bytes innerhalb der Vereinigung erfordern, dass auf sie zugegriffen wird als theUnion.b.b1 usw., was ziemlich nervig erscheint.

1422850cookie-checkWo sollen Include-Anweisungen, Header oder Quelle platziert werden?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy