Hallo,
ich hab eine Frage zur Verwendung von #include bzw. Header-Dateien.
Etwas googlen und suchen in den Forumsbeiträgen brachte mich zur
folgenden (etwas vereinfachten) allgemeinen Form:
1
/* header.h */
2
voidfunction_1(void);// Prototyp von function_1
3
voidfunction_2(void);// Prototyp von function_2
4
// usw.
5
6
7
/* header.c */
8
#include"header.h"
9
10
voidfunction_1(void)
11
{
12
// mach irgendwas..
13
}
14
15
voidfunction_2(void)
16
{
17
// mach irgendwas anderes..
18
}
19
20
21
/* main.c */
22
#include<...> // Standard-Bibliotheken einbinden
23
#include"header.h" // <-- hier setzt meine Frage an (siehe unten)
24
25
voidmain(void)
26
{
27
// Hauptprogramm..
28
}
Meine Frage ist nun, warum wird im Hauptprogramm die *.h-Datei
eingebunden und nicht die *.c-Datei?
Ok, aus der *.h kennt der Compiler erstmal die Prototypen. Ok, soweit so
gut. Aber woher kennt er dann die genaue Implementierung der Funktionen
(heisste das so?)? Wird einfach davon ausgegangen, dann *.h und *.c den
selben Namen haben?
Logischer für mich würde es irgendwie klingen, wenn ich im Hauptprogramm
die *.C einbinde. Die Datei wiederum bindet dann die *.h ein und die
Welt ist in Ordnung :-)
Sehe ich das richtig, dass ich auch einfach einige Funktionen in eine
*.c auslagern kann und dann mit include "xyz.c" einbinden kann, ohne
Header zu benutzen? (für nicht garzu allgemein nutzbare Funktionen vor
allem).
Gruß und schonmal Danke für Erleuchtung :-)
Christian
Zuallererst werden die include-Files im C-File eingefügt und auch alle
weiteren Preprocessor-Anweisungen durchgeführt, (alle Zeilen die mit "#"
beginnen) wie z.B. Macros substituieren.
Der Compiler übersetzt dann vorest jedes C-File einzeln zu einem
Object-File => *.o File. Anhand der Prototypen-Deklarationen nimmt er
an, dass die Funktion irgendwo in einem anderen Objectfile existiern
wird,fall sie nicht schon im selben C-File vorkommt und setzt die
entsprechenden Labels für den Linker.
Erst der Linker fügt dann alle Object-Files zu einem Programm zusammen.
Durch das Makfile weiss der Compiler+Linker welche Dateien zusammen
gehören bzw aus welchen Source-Dateien das Programmm zusammengebaut
werden soll.
Es können *.c UND *.h Dateien eigebunden werden. Ob man *.c Dateien
einbindet ist eigendlich nur eine Frage vom Programmierstil. Ob. die
Funktionsdeklaration in einer *.h Datei steht hängt davon ab, ob man mit
mehreren Dateien arbeitet und diese auf die Deklarierten Funkionen
zugreifen müssen. In deinem Beispiel ist eine *.h Datei nicht notwendig.
Ich persönlich halte es so, dass es in meinen Projekten nur eine Datei
MAIN.c OHNE MAIN.h gibt. In MAIN erfolgt dann nur die Initialisierung
und der Aufruf des Schedulers.
>Es können *.c UND *.h Dateien eigebunden werden.
Können kann man alles einbinden, aber wenn überhaupt, gibt es nur ganz
wenige Spezialfälle, wo das einbinden von .c-Dateien sinnvoll ist.
Normalerweise braucht man das nicht.
Das funktioniert so, wie Peter es schon beschrieben hat.
Oliver
Woher weiss der Compiler aber, dass die Datei Header.c mit übersetzt
werden muss? Die wird ja nirgends mittels #include oder so erwähnt.
(Meine Funktionen hab ich nun erstmal alle mittels #include "zeugs.c" in
eine andere Datei verlagert. So ists erstmal nicht garzu unübersichtlich
in der Hauptdatei. Um die Funktionen ordentlich in nem anderen Projekt
wiederverwenden zu können, müsste ich aber wohl einiges noch ein
bisschen allgemeiner Formulieren und einige Überprüfungen einbauen.)
Bitte mich weiter erleuchten :-) :-)
Gruß und Danke
Christian
Gast123 wrote:
> Woher weiss der Compiler aber, dass die Datei Header.c mit übersetzt> werden muss? Die wird ja nirgends mittels #include oder so erwähnt.
Durch das MAKEFILE. Oder auch dadurch, dass du alle C-Dateien der IDE
hinzufügst, mit der du programmierst.
> (Meine Funktionen hab ich nun erstmal alle mittels #include "zeugs.c" in
Sowas macht man nicht, auch wenn es (erstmal) funktioniert ;)
Der Compiler weiss es nicht. Er muss für jede Datei einzeln aufgerufen
werden. Erst der Linker erstellt daraus (wie bereits oben geschrieben)
"eine" fertige Programmdatei.
Damit man nicht jede Datei einzeln kompilieren und anschließend den
Linker (vereinfacht ausgedrückt: den Zusammensetzer) aufrufen muss, gibt
es die sogenannten Make-Dateien. Das ist soetwas wie eine Skriptdatei
die vorher definierte Abläufe durchführt. In dieser Make-Datei muss jede
*.c Datei eingetragen werden so dass sie vom Compiler nach und nach
übersetzt wird. Jede c-Datei für wird für sich und ohne Wissen der
anderen Objektdateien übersetzt. Damit nun Aufrufe aus anderen *.c
Dateien nicht zu fehlern führen geht der Compiler davon aus, dass alle
Funktionen die in Headerdateien definiert sind, beim linken mit in das
endgültige Programmpaket eingefügt werden.
Steffen.
# List C source files here. (C dependencies are automatically generated.)
11
SRC=$(TARGET).c#<---HIER?
12
13
14
# List Assembler source files here.
15
# Make them always end in a capital .S. Files ending in a lowercase .s
16
# will not be considered source files but generated files (assembler
17
# output from the compiler), and will be deleted upon "make clean"!
18
# Even though the DOS/Win* filesystem matches both .s and .S the same,
19
# it will preserve the spelling of the filenames, and gcc itself does
20
# care about how the name is spelled on its command-line.
21
ASRC=
22
...
Aaaaah, langsam beginne ich zu verstehen :-) :-) Also könnte ich in dem
obigen Schnipsel aus dem makefile meine Datei zeugs.c eintragen (und
nicht per #include im Hauptprogramm). Die Datei würde dann separat
übersetzt werden. Dann würde aber wohl der Compiler beim hauptprogramm
meckern, weil er die Funktionen nicht kennt. Das wiederum würde man
durch die zeugs.h umgehen, die die Funktionsprototypen enthält.
Nur #include "zeugs.h" im Hauptprogramm, ohne die zeugs.c im Makefile zu
erwähnen würde also nicht funktionieren.
Ist das soweit richtig.. ? :-)
Vielen Dank und nen schönen Abend noch :-)
Christian
Gast123 wrote:
> Nur #include "zeugs.h" im Hauptprogramm, ohne die zeugs.c im Makefile zu> erwähnen würde also nicht funktionieren.>> Ist das soweit richtig.. ? :-)
Jep genau. Das Kompilieren würde zwar funktionieren, aber beim Linken
meldet der Linker dann, dass er bestimmte Objekte (also die Funktionen),
die der Compiler in das Objectfile eingtragen hat, nicht finden kann.
Demzufolge muss man das makefile also immer anpassen. Bisher dachte ich,
das wäre nur bei Änderung am Prozessortyp oder der Taktfrequenz
notwendig.
Juhu, ich glaub ich habs verstanden :-)
Vielen Dank an alle fleißigen Erklärer :-)
Gruß und noch ein schönes Wochenende
Christian
Momentan verwende ich WinAVR. Das AVR-Studio hatte ich vor einer Weile
für ASM benutzt, aber seit einem Weilchen soll das ja auch C verstehen.
Werd ich demnächst ausprobieren. Wobei die Modifikation am Makefile nun
auch nicht die große Sache ist - wenn man erstmal kapiert hat dass und
warum es erforderlich ist :-)
Gruß
Christian