Forum: Mikrocontroller und Digitale Elektronik [erledigt] C: Wie Header-Dateien richtig einbinden?


von Terence S. (takeshi)


Lesenswert?

Um Verwirrung vorzubeugen, mir geht es nicht darum, wie ich 
Header-Dateien einbinde, das ist mir klar. Mir geht es im die Struktur, 
um die Aufteilung im Projekt und die Verknüpfungen untereinander.

Fiktives Projekt: Ich habe mehrere Programm- und zugehörige 
Header-Dateien, zum Beispiel eine für Messungen über den ADC, eine für 
die Ansteuerung des Displays über SPI oder I²C und wieder eine zum 
Erzeugen einer PWM. Außerdem wäre da noch eine Header-Datei mit ein paar 
Typdefinitionen, die ich in mehreren anderen Dateien verwende.

Nun brauche ich in den jeweiligen Programmdateien die zugehörige 
Header-Datei und eine oder mehrere Header-Dateien der MCU-Bibliotheken. 
In der main-Funktion brauche ich wiederum die Header-Dateien aus meinem 
Projekt, damit ich die Funktionen aufrufen kann.

Wie macht ihr das? Um ggf. besser verständlich zu machen, was ich meine, 
zwei Beispiele.

- Eine stumpfe Möglichkeit wäre eine Header-Datei anzulegen, in der alle 
benötigten Header-Dateien eingebunden werden und die binde ich dann 
wiederum in jeder anderen Datei ein. Nur das ist sicher nicht die 
schönste Methode, auch wenn es funktioniert.
- Eine andere Möglichkeit wäre es die Header-Datei, die zu jeder 
Programm-Datei gehört, darin einzubinden, sowie die Header-Dateien der 
MCU-Bibliotheken, die für diese Programmdatei benötigt werden. In der 
main-Datei binde ich dann alle Header-Dateien aus dem Projekt noch 
einmal ein. Das hätte den Vorteil, dass jede Datei alles einbindes, was 
sie selbst braucht, jedoch muss ich so einige Header-Dateien viele Male 
einbinden (eine sogar überall), was wie die vorherige Methode nicht zu 
einem Fehler führt, aber mir trotzdem unschön vorkommt. Und in den 
MCU-Bibliotheken wird das auch nicht so gemacht, da wird gern 
verschachtelt eingebunden.

Wie macht es der gelernte Programmierer? Das ist leider eines der 
Themen, zu denen ich nie etwas gefunden habe.

Danke schon mal!

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Jede Datei hat inkludiert alle Header, die benötigt werden. Nicht mehr 
und nicht weniger. Das gilt auch für Header-Dateien…

Oliver

von Stefan F. (Gast)


Lesenswert?

Jede Klasse (bzw. Gruppe zusammen gehörender Funktionen) bekommt jeweils 
eine eigene Header Datei, und die wird nur dort eingebunden, wo sie 
benötigt wird.

Einfach mal überall pauschal alles Einbinden verbirgt die Abhängigkeiten 
und macht den Compiler langsam.

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Du bindest in jeder Quelltextdatei genau die Header ein die du in dieser 
Datei brauchst, nicht mehr und nicht weniger. In den Headern bindest du 
genau die Header ein die du zwingend im jeweiligen Header(!) brauchst, 
also eher nur für Datentypen, etc.

: Bearbeitet durch User
von Jester (Gast)


Lesenswert?

Ist weitgehendst Geschmacksache...

https://www.mikrocontroller.net/articles/Include-Files_(C) hilf Dir 
nicht weiter?

von EAF (Gast)


Lesenswert?

Terence S. schrieb:
> jedoch muss ich so einige Header-Dateien viele Male
> einbinden (eine sogar überall), was wie die vorherige Methode nicht zu
> einem Fehler führt, aber mir trotzdem unschön vorkommt.

Das "Komisch"  dar einen nicht stören.
Wenn eine *.h 5 mal gebraucht wird, dann ist das so.
Davon kriegt man doch keine Gefühle.

Der Include Guard verhindert Probleme damit. Dafür wurde er erfudnen.

von Terence S. (takeshi)


Lesenswert?

Vielen Dank an alle, das ist ziemlich einstimmig. Ich war mir nur 
unsicher, weil mir das wie gesagt in den Bibliotheken der 
Mikrocontroller sehr verschachtelt vorkommt. Da kann ich mich teilweise 
durch einige includes wurschteln, bis ich bei der Deklaration angekommen 
bin.

Jester schrieb:
> https://www.mikrocontroller.net/articles/Include-Files_(C) hilf Dir
> nicht weiter?

Doch, das ist gut und entspricht der Aussage aller hier, das habe ich 
nur bisher nicht gefunden.

-> Thema erledigt

von A. S. (Gast)


Lesenswert?

Terence S. schrieb:
> Da kann ich mich teilweise
> durch einige includes wurschteln, bis ich bei der Deklaration angekommen
> bin.

In der Regel gibt es nur eine oder wenige Deklarationen einer Variable 
in den Quelltexten. Die findet Deine IDE wenn sie für das Projekt 
richtig aufgesetzt ist (z.B. per Makefile) und Du z.B. mit der Maus 
drauf stehen bleibst (oder rechte Maustaste oder so)

von Stefan F. (Gast)


Lesenswert?

Terence S. schrieb:
> Da kann ich mich teilweise durch einige includes wurschteln,
> bis ich bei der Deklaration angekommen bin.

In den mir bekannten IDE klickt man mit gedrückter Strg-Taste auf eine 
Funktion und schon öffnet sich die Deklaration.

von Terence S. (takeshi)


Lesenswert?

Mit F3 komme ich in Eclipse auch sofort da hin. Nur möchte ich wissen, 
über welchen Weg die Datei eingebunden wird, kann ich schon mal ein 
bisschen suchen, da sie manchmal nicht von der Datei direkt eingebunden 
wird, die sie benötigt. Wenn ich wissen will, woher eine konkrete 
Bibliotheks-Datei weiß, was uint16_t ist, kann der Weg lang sein, auch 
wenn ich per Tastenkombi sofort dort hin gelange. Aber das war wie 
gesagt nicht mein Problem, das passt schon so.

von I fill out this field (Gast)


Lesenswert?

Terence S. schrieb:
> Wenn ich wissen will, woher eine konkrete
> Bibliotheks-Datei weiß, was uint16_t ist, kann der Weg lang sein,

Nicht, wenn Du den Preprozessor Output (z.B per gcc -E o.ä erzeugt)
anschaust.

$ man gcc
       If you use the -E option, nothing is done except preprocessing. 
Some of these options
       make sense only together with -E because they cause the 
preprocessor output to be
       unsuitable for actual compilation.


Da stehen die expandierten Header einschliesslich der
Dateinnamen drin. Das Problem mit Macrodefinitionen und -expansionen
scheint evtl. per -fpreprocessed Option lösbar zu sein:

-fpreprocessed
           Indicate to the preprocessor that the input file has already 
been preprocessed.  This
           suppresses things like macro expansion, trigraph conversion, 
escaped newline splicing,
           and processing of most directives.  The preprocessor still 
recognizes and removes
           comments, so that you can pass a file preprocessed with -C to 
the compiler without
           problems.  In this mode the integrated preprocessor is little 
more than a tokenizer
           for the front ends.

lösbar zu sein (hab's nicht ausprobiert).

Dein Compiler hat sicher vergleichbare Otionen.

von I fill out this field (Gast)


Lesenswert?

Oder mit einer der gcc -M Optionen eine Liste der Headerfiles ausgeben 
lassen und den Inhalt derer per "cat" zusammenhängen. Das lässt sich 
wahrscheinlich mit einem Einzeiler Shellscript automatisieren.

$man gcc
...
       -M  Instead of outputting the result of preprocessing, output a 
rule suitable for make
           describing the dependencies of the main source file.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.