Hallo, eigentlich komme ich mit den im Betreff genannten Dateien mittlerweile gut zurecht. In den C-Dateien stehen nur noch die Funktionen, in den H-Dateien nur deren Deklarationen und die globalen Variablen. In der C-Datei wird dann jeweils oben "#include "xyz.h" hingeschrieben. In den H-Dateien kommt noch die Anweisung #ifndef ... usw. hin. So kann ich auch prima Querzugriffe zwischen den einzelnen Bibliotheken meines Projektes machen. Will ich aber eine main.h definieren, in der ich ensprechend bestimmte H-Dateien per #include ... einbinde, so kann ich in meiner main.c (in der ganz oben #include "main.h" steht) nicht mehr auf die in denen enthaltenen Funktionen zugreifen. Wo liegt mein Fehler? Gruß, Mike
Hi sollte eigentlich bis zu einer gewissen Tiefe problemlos funktionieren. Compiler kaputt? Matthias
In den H-Dateien stehen die Prototypen. Muss ich in der main.h auch die main () als Prototyp definieren?
Hi nö. Kann dein Compiler nach dem Präprozessorlauf abbrechen und die Ergebnisse ausgebe? Dann kannst du sehen ob die .h richtig eingebunden werden. Matthias
"in den H-Dateien nur deren Deklarationen und die globalen Variablen." Falsch. Globale Variablen werden in einem C-File angelegt: int foo[16]; Im H-File steht nur der Prototyp: extern int foo[16]; oder extern int foo[]; // hier geht aber nicht mehr sizeof() #ifndef verwendet man nur dazu, um das File selber von einer Doppelausführung auszuschließen, nicht aber andere. Peter
Irgendwie raffe ich das nicht. Habe jetzt mal ein extrem simples Beispiel gemacht. 4 Dateien test.c test.h main.c main.h Habe in der main.h die Zeile #include "test.h" stehen. In der test.c steht #include "test.h" und in der main.c steht #include "main.h". Nur kann ich mit dieser Konfiguration nicht von der main.c auf die test.c zugreifen. Habe es mal angehangen, die Fehlermeldung liegt als Textdatei bei. Gruß, Mike
Hi Mike, du musst in "main.c" die Methoden aus "test.c" mit der "extern"-Deklaration bekannt machen, nicht in "test.h". Der Compiler muss wissen, dass es diese Methoden gibt, der Linker wird anschließend die passende Methode zuordnen. Also, in "main.c": extern void test(void); Nicht vergessen: "test.c" an den Linker übergeben! Da du anscheinend noch nicht so viel programmiert hast, beantworte dir mit geeigneter Literatur oder dem Internet folgende Fragen: 1. Welche Aufgabe hat der Präprozessor? 2. Welche Aufgabe hat der Compiler und wie parametriere ich ihn? 3. Welche Aufgabe hat der Linker? 4. Wie benutze ich make, bzw. wie erstelle ich ein Makefile? Programmieren ist am Anfang ein langsamer Prozess, später wird es schwierig :-) Viele Grüße Rolf
Na, das ist so nicht ganz richtig! Er muss die Prototypen nicht in der main.c einbinden, sondern besser in der test.h. Da alle Prototypen mit "extern" versehen -- fertig.
Irgendwie bin ich jetzt nicht wirklich schlauer. Wenn ich in der main.c alle Funktionsprototypen nochmal hinschreiben muss, dann kann ich mir das alles auch schenken. Lasse ich die main.h weg und schreibe oben in die main.c die Anweisung #include "test.c" , #include "test2.c" usw. dann kann ich beliebig auf alle Routinen zugreifen. Hatte mir nur gedacht, dass es eine Möglichkeit gibt, dem Schema treu zu bleiben und auch eine main.h nach dem selben Muster wie bei den anderen C-Dateien zu erstellen. Wie dem auch sei, erstmal danke für eure Ratschläge. Gruß, Mike
Huiuiui... MOMENT! :) Ein kleines Beispiel: ---- test.h: extern void foo(void); ---- test.c: void foo(void) { /* irgendwas */ } ---- main.c: #include "test.h" int main(void) { foo(); return 0; }
Wenn im main.c das #include "test.c" funktioniert, dann liegt der Fehler in Deiner make-Datei. Du must sowohl test.c als auch main.c compilieren und dann test.o + main.o linken. Ich benutze den GCC ohne make auf der Kommandozeile und sage ihm als Quelldatei *.c. Damit sucht er sämtliche *.c im aktuellen Verzeichnis zusammen, compiliert sie und link sie alle. Das make kann leider nicht *.c automatisch expandieren. Da must Du jede einzelne Datei zu Fuß mit einbinden. Peter
Als Makefile dient das im WinAVR-Paket enthaltene Beispiel ohne jegliche Anpassung (außer Programmierdongle, MCU und Ziedatei).
Nein, Peter, das hat mit dem Makefile nichts zu tun. Wenn er #include "foo.c" macht, dann macht der Präprozessor nichts anderes, als den Inhalt von foo.c an der stelle des Includes einzufügen. D.h. der Code von foo.c steht in der gleichen Datei. Damit werden die Prototypen "überflüssig" (nicht wirklich, aber für die Erklärung reichts). Wenn im Code darunter dann diese Funktionen (scheinbar aus foo.c) verwendet werden, gibts keine offenen Referenzen.
O.k., mal etwas Licht ins Dunkle schicken: ich hatte nicht gesehen, dass in "main.h" auch noch "#include <test.h>" steht. So sind natürlich die Prototypen bekannt. Aber so weiß der Linker noch immer nicht, was er zu tun hat. Das erklärt auch die Ausgabe "undefined reference": die Datei "test.c" ist dem Linker nicht bekannt! Durch das "#include <test.c>" ist natürlich keine extern-Deklaration mehr notwendig, da nun die Dateien "test.c" und "main.c" vom Präprozessor "zusammengebaut" werden. Mit meiner ersten Antwort wollte ich nicht verwirren, aber wichtig ist es, den Weg vom Quellcode zur ausführbaren Datei zu verstehen. Viele Grüße Rolf
>> die Datei "test.c" ist dem Linker nicht bekannt!
ich meine natürlich die Datei "test.o", welche aus
"test.c" erzeugt wird ;-)
@ Rolf Theisinger >Aber so >weiß der Linker noch immer nicht, was er zu tun hat. Das erklärt auch >die Ausgabe "undefined reference": die Datei "test.c" ist dem >Linker nicht bekannt! Und was muss ich nun machen. Im Makefile was ändern?
Auszug aus dem makefile: ---- # List C source files here. (C dependencies are automatically generated.) SRC = $(TARGET).c # If there is more than one source file, append them above, or modify and # uncomment the following: #SRC += foo.c bar.c # You can also wrap lines by appending a backslash to the end of the line: #SRC += baz.c \ #xyzzy.c ---- # uncomment the following: #SRC += foo.c bar.c Wenn Du das in SRC += test.c änderst, dann sollte alles Kompiliert und gelinkt werden.
@OldBug "Nein, Peter, das hat mit dem Makefile nichts zu tun." Doch. Wenn der Linker nämlich test.o mit linken würde, müßte er dann meckern, daß die Funktion test() zweimal existiert. Da er aber nicht meckert, ist also das make-File falsch. Peter
Hi Mike, dein Programm ist ja schon modular aufgebaut. Du hast mehrere Dateien, in denen deine Methoden stehen. Um Verwechslungen und mehrfache #inlcude-Direktiven zu vermeiden, solltest du nach Möglichkeit die Headerfiles des einen Moduls (hier test) nicht in den Headerfiles des anderen (hier main) einbauen, sondern in den Code-Files (hier main.c). In deinem Fall ist das jedoch nicht nötig. Ebenso ist es nicht nötig, eine Datei "test.h" mit extern-Deklarationen zu erstellen, da du dem Linker eigentlich anweist, in einem anderen Modul nach der Methode zu suchen. Gleichzeitig bindest du "test.h" in "test.c" ein, wo es auch eine Methode "void test(void)" gibt. Ganz kurz: der Compiler erzeugt aus den vom Präprozessor zusammen gestellten Datein die object-Dateien (Endung .o). Diese Module werden dann vom Linker zusammen gebracht und es wird eine ausführbare Datei erzeugt. Dein Programm wird kompiliert, wenn du 1. "#include <test.h> aus "main.h" entfernst 2. die extern-Deklarationen aus "test.h" entfernst für "void test(void) brauchst du dort keinen Prototypen angeben. 3. den Datentyp von i ändern. i++ und i-- werden von einem C-Compiler übrigens nicht erkannt (C++)!!! Ganze Zahlen <=> int!!! 4. extern void test(void) nach main.c 5. "main.h" löschen, extern void main(void) macht keinen Sinn, sollte auch eher sowas sein wie int main (int argc, char** argv) 6. gcc -c test.c -o test.o übersetzt dir "test.c" ohne Linker 7. gcc -c main.c -o main.o entsprechend für "main.c" 7. gcc -Wall -pedantic -o main main.o test.o erstellt dir eine ausführbare Datei mit Namen main und benutzt hierfür die Module main.o und test.o (ja, sie werden gelinkt). Vielleicht probierst du es erstmal ohne Makefile, liest dich dann in die Materie ein (siehe meine erste Antwort). Viele Grüße und viel Erfolg (habe jetzt keine Zeit mehr :-) Rolf
@ OldBug Danke für den Hinweis. @Peter Wenn du mit falsch meinst, dass im Makefile die von OldBug genannten Zeilen fehlen, dann hast du natürlich recht. Auch wenn mir sein Posting trotz allem mehr geholfen hat.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.