Was ist der grundlegende Unterschied zwischen Quell- und Header-Dateien in C?

Lesezeit: 5 Minuten

Benutzeravatar von Delan Azabani
Delan Azabani

Ich verstehe nicht ganz, wie die Dinge in den Quell- und Header-Dateien von C getrennt werden sollten. Ich sehe oft viele Projekte mit zwei Sätzen von Dateien mit demselben Namen (eine Erweiterung bezeichnet eine Quelle und eine andere eine Header-Datei).

Aus diesem Mangel an Verständnis heraus habe ich bisher, wenn ich Bibliotheken geschrieben habe, den gesamten Klassen- und Klassenmethodencode in eine Datei geschmissen, ohne mich bei der Wahl der Dateierweiterung zu entscheiden.

Was sollte in Headern und was in den Quelldateien stehen? Wie setze ich diese Trennung um?

Benutzeravatar von Thomas
Thomas

Es gibt kein technisch Unterschied. Der Compiler lässt Sie gerne a einbinden .c Datei, oder kompilieren Sie eine .h Datei direkt, wenn Sie möchten.

Es gibt jedoch eine riesige kulturell Unterschied:

  • Erklärungen (Prototypen) hineingehen .h Dateien. Das .h Datei ist die Schnittstelle zu was auch immer in der entsprechenden implementiert ist .c Datei.

  • Definitionen hineingehen .c Dateien. Sie implementieren die in der angegebene Schnittstelle .h Datei.

Der Unterschied besteht darin, dass a .h Datei kann (und wird normalerweise) sein #included in mehrere Übersetzungseinheiten (.c Dateien). Wenn du definieren eine Funktion in a .h Datei, es wird in mehreren enden .o Dateien, und der Linker wird sich über ein mehrfach definiertes Symbol beschweren. Deshalb sollten Definitionen nicht hineingehen .h Dateien. (Inline-Funktionen sind die Ausnahme.)

Wenn eine Funktion in a definiert ist .c Datei, und Sie möchten sie von anderen verwenden .c Dateien, muss eine Deklaration dieser Funktion in jeder dieser anderen verfügbar sein .c Dateien. Deshalb setzen Sie die Deklaration in a .hund #include das in jedem von ihnen. Sie könnten die Erklärung auch in jedem wiederholen .c -Datei, aber das führt zu viel Code-Duplizierung und einem unkontrollierbaren Durcheinander.

Wenn eine Funktion in a definiert ist .c Datei, aber Sie nicht möchte es von anderen verwenden .c Dateien, muss es nicht im Header deklariert werden. Es ist im Wesentlichen ein Implementierungsdetail davon .c Datei. Machen Sie in diesem Fall die Funktion static auch, sodass es nicht zu Konflikten mit gleichnamigen Funktionen in anderen Dateien kommt.

  • Obwohl der Standard nichts vorschreibt, hängen leider die meisten Compiler, die ich verwendet habe, bis zu einem gewissen Grad von der Dateierweiterung ab. Versuchen Sie Folgendes: Erstellen Sie zwei Dateien mit (sagen wir, int main(){return 0;}) genannt header.c und header.h und versuche sie mit gcc zu kompilieren. (Ich komme nicht einmal in die Nähe von VS!)

    – dirkgent

    14. August 2010 um 11:12 Uhr

  • Ich vermute, dass die meisten Programmierer die Deklarationen statischer Funktionen nicht in die .h-Datei einfügen. Der Hauptunterschied zwischen .h und .c besteht zwischen Schnittstelle und Implementierung.

    – Messstab

    14. August 2010 um 11:18 Uhr

  • @dirkgently: Okay, aber Ihr Compiler fungiert nicht als C-Compiler, wenn er nicht die richtige Dateierweiterung erhält. Der Standard sagt nichts über Programme aus, die keine C-Compiler sind 🙂

    – Thomas

    14. August 2010 um 11:28 Uhr

  • @Thomas: Du hast meinen Beitrag nicht richtig gelesen. Die Norm sagt Quelle und Header Dateien und schreibt keine bestimmten Erweiterungen für sie als solche vor. Und ja, versuchen Sie das Snippet, das ich mit der Befehlszeile gepostet habe: gcc -Wall -ansi -pedantic -std=c99 -o header und sehen, was Sie bekommen.

    – dirkgent

    14. August 2010 um 11:32 Uhr

  • Vorkompilierte Header sind ein Muss in jedem Projekt von beträchtlicher Komplexität. Die meisten Compiler haben heutzutage Schalter, um eine bestimmte Datei anzuzeigen, die Sie für die Vorkompilierung markieren möchten. Außerdem müssen sie normalerweise in jeder Quelle enthalten sein.

    – dirkgent

    14. August 2010 um 12:39 Uhr

Was sollte in Headern und was in den Quelldateien stehen?

Typischerweise enthalten Header eines oder mehrere der folgenden Elemente:

  • Funktionsdeklaration (außer Statik)
  • Variablendeklaration (typischerweise global)
  • Benutzerdefinierte Typdeklaration (read struct, union etc.)
  • Makrodefinition

Quelldateien hingegen haben:

  • Funktions-/Variablendefinition
  • Statische Funktionsdeklaration und -definition (Sie möchten diese Ihren Clients nicht aussetzen)
  • Variablendefinition
  • Einige ziehen es vor, Inline-Funktionen (C99) in einem Header zu definieren

Wie setze ich diese Trennung um?

Die One Definition Rule ist dein Freund.

Denken Sie daran, wenn Sie eine Bibliothek schreiben, ist dies das, was Ihr Kunde zu sehen bekommt. Seien Sie also hilfreich und stellen Sie ihnen alle Informationen zur Verfügung, damit sie Ihre Bibliothek verwenden können. Die Quelldateien werden typischerweise in Binärform kompiliert und bereitgestellt.

Übrigens hat C kein Klassenkonzept.

  • struct ist nah genug für mich 🙂

    – Delan Azabani

    14. August 2010 um 10:54 Uhr

  • Wenn “The One Definition Rule” Gold ist, ist “Don’t tell” Silber. Damit meine ich, dass keine privaten Details in Header-Dateien eingefügt werden. Wenn Sie eine Bibliothek eines Drittanbieters erstellen, müssen Sie alles, was Sie in die Header-Datei einfügen, in Zukunft unterstützen. Wenn Sie in großen Projekten arbeiten, fördert das Minimieren von Header-Dateien das Refactoring, da es die Kompilierzeit verkürzt, wenn Sie die Header-Dateien tatsächlich ändern müssen. (Ich war in einem Projekt, bei dem es 12 Stunden gedauert hat, es neu zu kompilieren, wenn Sie zentrale Header-Dateien geändert haben. 12 Stunden x # Anzahl der Entwickler = Geld.)

    – Nur ein weiterer Metaprogrammierer

    14. August 2010 um 11:09 Uhr

Normalerweise enthalten Header-Dateien Deklarationen, Quelldateien enthalten Code.

Also, wenn in der Quelldatei A.c Sie benötigen eine in der Quelldatei implementierte Funktion B.cSie schließen einfach ein B.h seine Erklärung haben.

Es gibt kaum einen grundlegenden Unterschied zwischen .c- und .h-Dateien (obwohl einige Compiler sich möglicherweise weigern, eine rohe .h-Datei zu kompilieren). Der Unterschied liegt eher in der Konvention.

Normalerweise stellt die .h-Datei die API und die .c-Datei die Implementierung bereit.

Daher würde die .h-Datei nur Dinge enthalten, die von anderen Quelldateien benötigt werden, um auf die von Ihrer .c-Datei bereitgestellten Einrichtungen zuzugreifen. Die .h-Dateien würden also die Funktionsprototypen globaler Funktionen, Deklarationen globaler Variablen (wenn Sie sie wirklich haben müssen) und die Strukturen und andere von ihnen verwendete Typen bereitstellen. (Stellen Sie keine Struktur bereit, wenn nur ein Zeiger auf die Struktur von der API benötigt wird.)

Inline-Funktionen sind auch oft in .h-Dateien enthalten, aber einige Codierungsrichtlinien bevorzugen die Verwendung einer separaten Erweiterung (z. B. .inl).

Alle anderen Funktionsimplementierungen, die Definition und Initialisierung von Variablen und Deklarationen von lokalen (statischen) Variablen und Funktionen wären in der .c-Datei.

1413940cookie-checkWas ist der grundlegende Unterschied zwischen Quell- und Header-Dateien in C?

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

Privacy policy