www.mikrocontroller.net

Forum: Compiler & IDEs Header und C-Dateien


Autor: Mike (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

sollte eigentlich bis zu einer gewissen Tiefe problemlos funktionieren.
Compiler kaputt?

Matthias

Autor: Dirk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

Prototypen angelegt?

Mfg

Dirk

Autor: Alex (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In den H-Dateien stehen die Prototypen.
Muss ich in der main.h auch die main () als Prototyp definieren?

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"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

Autor: Mike (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf Theisinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: OldBug (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Mike (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: OldBug (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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;
}

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Mike (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Als Makefile dient das im WinAVR-Paket enthaltene Beispiel ohne jegliche
Anpassung (außer Programmierdongle, MCU und Ziedatei).

Autor: OldBug (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Rolf Theisinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf Theisinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>> die Datei "test.c" ist dem Linker nicht bekannt!

ich meine natürlich die Datei "test.o", welche aus
"test.c" erzeugt wird ;-)

Autor: Mike (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ 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?

Autor: OldBug (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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

Autor: Rolf Theisinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Mike (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.