Forum: Compiler & IDEs Struktur von Source- und Headerfiles


von Markus (Gast)


Lesenswert?

Hallo

Ich möchte mein Source file thematisch in mehrere Sourcefiles 
aufsplitten, ich erhalten stänig Fehlermeldungen und hab jedoch Mühe, 
welche Angaben ins .h und welche ins .c-File kommen. Ich versteh das ich 
das mit den Direktiven (insbesondere mit #ifndef ..#endif und #include) 
nicht.
Konkret hab ich die Files

menu.c, menu.h
darin sind u. a. 2 structs definiert.
1
typedef struct A { struct *B; ... } A;
und
1
typedef struct B { struct *A; uint8_t var; ...} B;

Ich brauche also eine forward declaration. Soll die ins header-file? 
Brauche ich im .h-File #ifndef ..#endif Direktiven? Und wo muss ich die 
#include <avr/io.h> Direktive (für die Definition des uint8_t-Datentyps) 
einfügen? Der Variablentyp wird natürlich dann auch noch in anderen .c 
files verwendet.

lcd.c, lcd.h
ist es sinnvoll Definitionen von Konstanten wie #define  LCD_RS PD5 im 
lcd.c, lcd.h oder gar im main.c zu definieren?

main.c, main.h
wie muss ich nun die menu.h und lcd.h (oder die files menu.c und 
menu.c?) in die main.c (oder main.h?) einbinden?

Bin sehr froh um eure Hilfe
Makrus

von Markus (Gast)


Lesenswert?

... an den Struct-Definitionen liegts nicht, die heissen nämlich korrekt 
(nicht wie im vorigen Beitrag):
1
typedef struct A { struct B *structTyp1; ... } A;
1
typedef struct B { struct A *structTyp2; uint8_t var; ...} B;

von Helfer (Gast)


Lesenswert?

Markus schrieb:
> Ich brauche also eine forward declaration. Soll die ins header-file?
Ja.

> Brauche ich im .h-File #ifndef ..#endif Direktiven?
Nicht wirklich, ist aber eine gute Idee -> machen.

> Und wo muss ich die
> #include <avr/io.h> Direktive (für die Definition des uint8_t-Datentyps)
> einfügen?
Ins .c file. Jedes .c file muss sich ohne Fehler/Warnungen compilieren 
lassen (also nicht den Linker anwerfen, nur object erzeugen). Im .c file 
holst du dir das zugehörige header file rein (include), damit prüfst du 
auch immer die Konsistenz.

von Karl H. (kbuchegg)


Lesenswert?

Markus schrieb:

> menu.c, menu.h
> darin sind u. a. 2 structs definiert.
>
1
> typedef struct A { struct *B; ... } A;
2
>
> und
>
1
> typedef struct B { struct *A; uint8_t var; ...} B;
2
>
>
> Ich brauche also eine forward declaration. Soll die ins header-file?

Es ist ganz einfach.

Schau dir dein Header File an. Nur dieses eine Header File.
Lies es von oben nach unten.

Welche Begriffe kommen vor, die nicht Bestandteil der Sprache C sind 
(wie zb typedef ja ein Schlüsselwort ist). Für alles, was nicht in 
diesem Sinne Bestandteil von C ist, brauchst du eine Form der 
Deklaration ehe du diesen Begriff dann tatsächlich verwenden kannst. 
Verwenden im Sinne von: diesen Begriff zur Definition von Variablen 
benutzen, Memberzugriffe in Strukturen etc.

Jetzt gibt es 3 Möglichkeiten
* entweder du kannst einfach die Reihenfolgen der Deklarationen tauschen

* oder das was du benötigen würdest ist in einem anderen Header File,
  dann kommt ein entsprechender #include rein

* oder du brauchst eine Forward Deklaration.
  Eine Forward Deklaration sagt dem Compiler: "Hör mal, das Teil gibt 
es.
  Ich hab da keinen Tippfehler gemacht. Ich kann dir zwar jetzt keine
  Details nennen, aber eine Struktur dieses Namens existiert
  tatsächlich".
  So eine Forward Deklaration ist gut genug, dass man zb einen Pointer
  auf eine STruktur machen kann. Denn wie groß ein Pointer sein muss
  das weiß der Compiler. Was er aber nicht weiß: Ob du dich vertippt
  hast, und die Struktur in Wirklichkeit ganz anders heißt.
  Mit einer Forward Deklaration behebst du dieses Wissens-Manko
  des Compilers.

> Brauche ich im .h-File #ifndef ..#endif Direktiven?

Das kommt drauf an.
Meistens braucht man sie nicht wirklich. Da es sich aber nicht lohnt 
darüber groß nachzudenken, macht man einfach überall Include Guards 
rein. Ist eine Sache auf 5 Sekunden und geht schneller als sich groß den 
Kopf über die Notwendigkeit zu zerbrechen.

> Und wo muss ich die
> #include <avr/io.h> Direktive (für die Definition des uint8_t-Datentyps)

dort wo du sie brauchst.

verwendest du uint8_t?
Wenn ja, dann brauchst du einen include auf stdint.h (wird von avr/io.h 
reingezogen. avr/io.h ist fein, inkludiert aber eigentlich schon etwas 
zu viel. Du kaufst dir ja auch nicht einen 3-er BMW, weil dir die 
BMW-Parkscheibe so gefällt. Kaufst du einen, kriegst du eine Parkscheibe 
mit dazugeliefert. Aber die Parkscheibe haben zu wollen ist kein Grund 
einen 3-er zu kaufen.)


> ist es sinnvoll Definitionen von Konstanten wie #define  LCD_RS PD5 im
> lcd.c, lcd.h oder gar im main.c zu definieren?

Das kommt drauf an, was mit diesen Konstanten bezweckt wird.
Wird diese Konstante nur im C File verändert und hat keine 
Konfigurationswirkung, dann sollte sie auch nur im C-File sein.
Gehört diese Konstante auch im weitesten Sinne zur 'äusseren 
Schnittstelle' des C-Files, dann gehört sie ins Header File.

> wie muss ich nun die menu.h und lcd.h (oder die files menu.c und
> menu.c?) in die main.c (oder main.h?) einbinden?

mit einem include

von Karl H. (kbuchegg)


Lesenswert?

Und noch ein Link

http://www.mikrocontroller.net/articles/Include-Files_(C)

und dann auch noch die >>>FAQ<<<  speziell Kapitel 6 und 7

von Andreas B. (andreas_b77)


Lesenswert?

Markus schrieb:
> menu.c, menu.h
> darin sind u. a. 2 structs definiert.

Wo jetzt, im menu.c oder menu.h?

>
1
> typedef struct A { struct *B; ... } A;
2
>
> und
>
1
> typedef struct B { struct *A; uint8_t var; ...} B;
2
>
>
> Ich brauche also eine forward declaration. Soll die ins header-file?

Die forward declaration wird für die Deklaration der structs benötigt. 
Also muss es auch dahin, wo die structs deklariert werden. Es macht 
keinen Sinn, eine forward declaration irgendwo in einen Header zu 
packen, wenn die eigentlichen Deklaration nicht auch dort sind.

> Brauche ich im .h-File #ifndef ..#endif Direktiven?

Musst du wissen. Es ist aber üblich, den kompletten Inhalt einer 
.h-Datei in ein ifdef einzuschliessen in der Form:
1
#ifndef MEINHEADER_H
2
#define MEINHEADER_H
3
4
...
5
6
#endif
Dabei ist MEINHEADER_H ein Symbol, das nur in dieser Datei vorkommt. Das 
sorgt dafür, dass der Inhalt ignoriert wird, falls der Header mehrmals 
in der selben Datei inkludiert wird.

> Und wo muss ich die
> #include <avr/io.h> Direktive (für die Definition des uint8_t-Datentyps)
> einfügen?

uint8_t wird (wie auch die anderen Standard-Typen) in stdint.h 
definiert. Und ein #include muss an den Anfang der Datei, in der es 
gebraucht wird.

> lcd.c, lcd.h
> ist es sinnvoll Definitionen von Konstanten wie #define  LCD_RS PD5 im
> lcd.c, lcd.h oder gar im main.c zu definieren?

Musst du wissen. Das #define ist nur dort wirksam, wo es im Text steht. 
Wird es in mehreren .c-Dateien gebraucht, dann muss es in eine .h-Datei, 
die von allen diesen .c-Dateien inkludiert wird.

> main.c, main.h
> wie muss ich nun die menu.h und lcd.h (oder die files menu.c und
> menu.c?) in die main.c (oder main.h?) einbinden?

Mit #include… Und eine .c-Datei wird nicht inkludiert, Punkt. Für einen 
Anfänger kann der letzte Satz ruhig als Dogma so stehen bleiben.

von Markus (Gast)


Lesenswert?

@Karl Heinz Buchegger: der Link ist leider nicht angekommen.

ok, vielen dank, hab jetzt einige fehler ausräumen können (insbesondere 
die beiden #include <stdio.h>, #include <avr/io.h> haben natürlich 
Konflikte verursacht:)

von Karl H. (kbuchegg)


Lesenswert?

Markus schrieb:
> @Karl Heinz Buchegger: der Link ist leider nicht angekommen.

Ah.
Das ist die Forensoftware.

Klick auf den Link, und ergänze dann händisch in der Adressleiste deines 
Browsers die fehlende ")" im Text von "(C)"

Dann klappts auch mit dem Link

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.