Indi schrieb:
> Für Klassen ect. habe ich das natürlich so umgesetzt und die .h Datei
> includiert.
> Bei einfachen Funktionen wollte ich mir das sparen.
> Aber das müsste doch so funktionieren oder nicht ?
Im Prinzip ja.
Aber wahrscheinlich vermutest du da wieder mal irgendeine Wunderwuzzi
Funktionalität hinter dem #include.
Ein #include ist eine ganz einfache Sache:
Er wird vom Präprozessor bearbeitet, der an dieser Stelle im Code ganz
einfach den Inhalt der angegebenen Datei einsetzt. Und erst das Ergebnis
dieser Ersetzung geht dann an den eigentlichen Compiler. Ein #include
ist nicht mehr als eine reine Textverarbeitungssache. Mehr passiert
dabei nicht.
Hast du Code in einer Datei main.c
1 | void foo()
|
2 | {
|
3 | mach was;
|
4 | }
|
5 |
|
6 | void bar()
|
7 | {
|
8 | mach was anderes;
|
9 | foo();
|
10 | }
|
11 |
|
12 | int main()
|
13 | {
|
14 | bar();
|
15 | }
|
und lagerst du die Funktion bar in eine eigene Datei bar.inc aus (ich
nenn das absichtlich nicht bar.c, eben weil hier die Funktion selbst
drinnen steht, die Datei aber nicht eigenständig compiliert werden
soll), dann hast du in main.c
1 | void foo()
|
2 | {
|
3 | mach was;
|
4 | }
|
5 |
|
6 | #include "bar.inc"
|
7 |
|
8 | int main()
|
9 | {
|
10 | bar();
|
11 | }
|
und bar.inc
1 | void bar()
|
2 | {
|
3 | mach was anderes;
|
4 | foo();
|
5 | }
|
Der Präprozessort schnappt sich die main.c und stösst irgendwann auf das
1 | ...
|
2 | #include "bar.inc"
|
3 | ...
|
das ist für ihn das Signal, diese Zeile rauszuwerfen und durch den
Inhalt der Datei bar.inc zu ersetzen. D.h. der Präprozessor führt die
beiden Einzelteile zusammen und erhält als Ergebnis den Text
1 | void foo()
|
2 | {
|
3 | mach was;
|
4 | }
|
5 |
|
6 | void bar()
|
7 | {
|
8 | mach was anderes;
|
9 | foo();
|
10 | }
|
11 |
|
12 | int main()
|
13 | {
|
14 | bar();
|
15 | }
|
den er dann an den eigentlichen C Compiler weiter gibt. Alles bestens.
Hast du das main.c aber so aufgebaut
1 | #include "bar.inc"
|
2 |
|
3 | void foo()
|
4 | {
|
5 | mach was;
|
6 | }
|
7 |
|
8 | int main()
|
9 | {
|
10 | bar();
|
11 | }
|
dann führt die Text-Einsetzung logischerweise zu
1 | void bar()
|
2 | {
|
3 | mach was anderes;
|
4 | foo();
|
5 | }
|
6 |
|
7 | void foo()
|
8 | {
|
9 | mach was;
|
10 | }
|
11 |
|
12 | int main()
|
13 | {
|
14 | bar();
|
15 | }
|
und wenn wir uns das ansehen, dann sehen wir, dass von oben nach unten
gelesen aus bar heraus eine Funktion foo() aufgerufen wird, von der zum
'Zeitpunkt' des Aufrufs noch nichts bekannt ist, weil sie ja im
Endergebnis unter der Funktion bar steht ohne dass es einen Prototypen
dafür gab. Und dann gibt es eben von deinem Compiler eine entsprechende
Warnung bzw. Error.
Fazit: ein #include ermöglicht dir, Einzelteile deines Codes auf mehrere
Dateien aufzuteilen, die in Textform vom Präprozessor wieder
zusammengesetzt werden, ehe das so erhaltene Machwerk dann zum Compiler
geht.
Wie du diese Aufteilung machst, ist deine Sache. Das interessiert weder
den Präprozessor noch den Compiler. Nur muss nach dem Präprozessor
gültiger C Code rauskommen.
Und ja: die übliche Form ist es, Funktionen in getrennt compilierbare
C-Files zu stecken, für die man dann ein Header File schreibt, welches
includiert wird. Dieses Vorgehen hat sich bewährt, auch wenn es nicht
vorgeschrieben ist und es durchaus auch Abweichungen davon geben kann
und gibt.
Aber grundsätzlich kann man den Präprozessor einfach nur als eine Art
Texteditor ansehen, der deinen Quelltext bearbeitet, ehe dann das
erhaltene Machwerk zum Compiler geht. Sinnigerweise stehen die
Anweisungen an diesen Texteditor im Text, den dieser spezielle Editor
bearbeitet. Aber recht viel mehr steckt da nicht dahinter.