Forum: PC-Programmierung externe H-Dateien und Funktionen in C


von Ralf (Gast)


Lesenswert?

Hallo miteinander,

habe nun mein erstes C-Projekt fast fertig. Da ich das ganze im
"Learning-by-doing"-Verfahren gemacht habe, fehlt mir offenbar noch
ein wenig Verständnis.

Folgender Sachverhalt: Ich habe das Projekt in "Module" gegliedert.
Module in dem Sinn, dass ich ein C-File habe, welches z.B. die serielle
Kommunikation abwickelt, ein Modul für die Display-Steuerung usw.
(Nebenbei, ich rede von C für Mikrocontroller, aber C ist C).

Okay, so weit so gut. Als Beispiel nehme ich jetzt mal das RS232-Modul.
Dort habe ich einen Verweis auf eine externe Routine, welche prüft, ob
das übergebene Zeichen ein ASCII-Hex-Zeichen (also "0" - "9" und
"A" bis "F") ist. Daher muss ich ja im RS232-Modul einen #include
Verweis auf das Modul machen, welches die Prüf-Routine enthält,
richtig?

Mein Problem ist, dass ich nicht direkt auf eine Routine in einem
bestimmten Modul verweisen möchte (was ja durch das #include
zwangsläufig passiert), sondern ich möchte nur den Namen der
entsprechenden Routine verwenden.
Das sichert mir die Unabhängigkeit der einzelnen Module voneinander.

Ist das machbar und/oder sinnvoll? Oder habe ich ein größeres
Verständnis-Problem, als ich dachte? ;-)

Dass ich in einigen Modulen zwangsläufig auf andere verweisen muss, ist
mir klar, aber ich möchte u.a. auch folgendes Problem lösen:

Da ich es wie bereits erwähnt bevorzuge, einzelne Module zu verwenden,
welche ein bestimmtes "Thema" abdecken, möchte ich erreichen, dass
diese Module (welche ja so eine Art "Treiber" darstellen), völlig
unabhängig voneinander funktionieren (also ohne Verweis auf ein
bestimmtes anderes Modul).

Hoffe, ich konnte mein Problem verständlich rüberbringen.

Gruß Ralf

PS: Vielleicht hat ja auch jemand einen Link, wo die Lösung solcher
Probleme angegangen wurde?

von Hans (Gast)


Lesenswert?

ähm... also zu allererst.. dir ist hoffentlich klar das du im include
nur .h files einbinden solltest... den code darf der compiler sich
selbst aus der .c generieren (darum gibst ja auch in der makefile deine
.c files an ;)

ich habe mir übrigeds eine tool-lib gebastelt...auf die haben alle
meine libs einen include stehn und die .c wird auch überall reingelinkt
(so heisst das übrigends wenn man aus den .obj/.o/... files die der
compiler produziert eine schöne ausführbare file macht ;)

wo ist also das genaue problem ??

willst du deine treiber von diesem (in meinem fall tool-lib) tool-modul
unabhängig machen ??? weil dann hilft nur copy-past von allem funktionen
die du brauchst... aber das macht wieder probs weil am schluss der
linker mäckern wird weil ein und die selbe funktion an mehrerern orten
definiert ist wenn du sie in mehrern modulen reintust

73

von Stefan (Gast)


Lesenswert?

Mit der Include-Datei machst Du dem "Modul" den Prototyp einer
Funktion bekannt. Die Funktion selbst kann in einem ganz anderen
"Modul" implementiert (in Code ausformuliert) sein.

In deinem Beispiel hättest Du die Funktionen für die serielle
Kommunikation in das Modul SERIELL13.C gesteckt und die für die
Displayansteuerung in das Modul DISPLAY45.C

Ich gehe ab jetzt davon aus, dass Du die Vorteile von Prototypen kennst
und NICHT darauf verzichten möchtest ;-)

Du kannst jetzt die Prototypen der Funktionen aus SERIELL13.C in der
Includedatei SERIELL.H halten und die für DISPLAY45.C in der
Includedatei DISPLAY.H.

Will eine Funktion aus SERIELL13.C eine Funktion aus DISPLAY45.C
benutzen, ist kann der Prototyp der Funktion durch ein #include
DISPLAY.H in SERIELL13.C bekannt gemacht werden.

Mehr als der Name, die Parameterübergabe (!!!) und der Rückgabetyp
(!!!) ist dem aufrufenden Modul nicht bekannt. Wie die Funktion dann in
dem anderen Modul implementiert (codiert) ist, sieht die aufrufende
Funktion nicht. Meinst Du das mit Unabhängigkeit?

Wenn es Dich nervt, mit vielen Includedateien umzugehen, kannst Du
mehrere Includedateien zusammenfassen. Zum Beispiel könntest Du alle
Prototypen von selbstprogrammierten Funktionen in RALF.H reinstecken
und diese Datei in allen Modulen mit #include RALF.H einbinden. Aber
schön ist das nicht.

Wenn es noch unabhängiger sein soll, kannst Du in jedem Deiner Module
ein Feld von Funktionszeigern einrichten. Ein Supervisormodul (z.B.
Dein Hauptprogramm) füllt die Funktionszeiger am Anfang auf und die
Module greifen auf andere Module zu, in dem sie die Funktionen über die
Funktionszeiger aufrufen statt direkt.

Aber Vorsicht: Nicht dass Du uns zu den objektorientierten Sprachen
entfleuchst ;-)

von Ralf (Gast)


Lesenswert?

Danke für die Antworten.

Und dann muss ich sagen: UUPS, natürlich arbeite ich mit Prototypen,
und die habe ich auch schön brav in den H-Files angegeben, und ich habe
natürlich auch nur die H-Files included.

Sorry, war keine Absicht, solch eine Verwirrung zu stiften ;-)

Vielleicht lässt sich mein Problem anders etwas verständlicher
ausdrücken:

Durch das #include bin ich immer an eine bestimmte Modul-Datei
gebunden.

Ich suche eine Möglichkeit, eine Funktion unabhängig vom Modul, in der
sie enthalten ist, bekannt zu machen.

Sagen wir als Beispiel, ich habe im Projekt A im Modul "RS232" eine
Routine "GET_ASC_HEX", die aus dem übergebenen ASCII-HEX-Zeichen
einen Hex-Wert generiert.

Jetzt erstelle ich Projekt B, das die gleiche Funktion braucht, aber
das RS232-Geraffel nicht. Statt dessen brauche ich die Funktion
"GET_ASC_HEX" im Modul "DISPLAY" von Projekt B.

Was ich nun als Lösung machen könnte, wäre die "GET_ASC_HEX" in ein
anderes Modul zu schreiben, z.B. Modul "HEX". Auf dieses Modul kann
ich in A von "RS232" aus mit #include "HEX.h" zugreifen. Das
gleiche gilt für Projekt B mit einem #include in "DISPLAY".

Jetzt geht es aber schon los, das werden ja zig Module! Und ich bin
wieder bei meinem Problem, ich habe wieder eine Abhängigkeit zu einem
anderen Modul. Das will ich aber für die TREIBER-Module VERHINDERN!
Dass das nötig ist für die eigentliche Applikation, ist klar, aber in
den Treiber Modulen möchte ich das eben verhindern. Dort möchte ich nur
sagen können, es gibt die Funktion in einem anderen Modul, aber ohne zu
sagen, in welchem Modul, was aber durch das #include nicht möglich
ist, denn ich muss ja den Modulnamen angeben.

Damit müsste sich doch die von mir gewünschte "Unabhängigkeit" der
Treiber erreichen lassen, oder?

Vielleicht ist diese Umschreibung verständlicher ;-)

ODER: Sind solche "Treiber-Module" immer stand-alone-fähig
geschrieben, d.h. ich kopiere den verwendeten Code immer direkt in das
Modul und verwende keinen Code aus anderen Modulen?
NOCH EIN ODER: Ist in Bezug auf das Schreiben solcher Treiber-Module
meine Vorgehensweise falsch?

Gruß Ralf

BTW: Ich habe gerade einen Blick in die bei C mitgelieferten H-Files
geworfen (stdio.h). Dort sind die Prototypen mit extern deklariert. Ist
das Schlüsselwort "extern" evtl. die Lösung für mein Problem? Oder
sagt das dem Compiler nur, dass er in einer Bibliothek zu suchen hat?

von Stefan (Gast)


Lesenswert?

Das Einbinden des Maschinencodes für eine Funktion in ein Programm macht
der Linker. Dazu werden binäre Objektdateien oder binäre Librarydateien
zum Hauptprogramm dazugebunden.

An der Stelle haben die Includedateien ihre Aufgabe längst getan. Die
Includedateien mit den Prototypen wurden vom Präprozessor benutzt, um
z.B. Typkontrollen durchzuführen.

Du kannst Millionen von Prototypen in eine Includedatei packen. Der
Präprozessor fischt sich nur die notwendigen (= die im Programm
benutzten) raus.

Dein eigentliches Problem hat mit den Includedateien nichts zu tun. Du
musst Dir überlegen, welche Funktionen Du sinnvoll in den verschiedenen
Libraries bzw. Quelltextdateien für einzelne Objektdateien
zusammenfasst.

Du kannst Dich an an dem Aufbau der Standard-C-Libraries orientieren.
Dein Beispiel mit HEX.C ist schon OK. Die Vielzahl der Module wird
üblicherweise reduziert, indem man mit einem Librarian die kleinen
Objektdateien der Module in einer Library zusammenfasst und der Linker
sich die benötigten herausfischt.

Und weil der Präprozessor auch angeln kann, legt man nicht für jede
Funktion eine einzelne Includedatei an, sondern fasst viele zusammen.
Im Extremfall packt man alle Windows Prototypen in eine fette windows.h
;)

von Stefan (Gast)


Lesenswert?

Ja, das "extern" zeigt dem Compiler, dass die Funktion nicht in dem
Quelltext implementiert (= in Code ausformuliert) wird, der gerade
bearbeitet wird.

Trifft der Compiler im Quelltext auf einen Funktionsaufruf einer
externen Funktion, wird er in der Objektdatei vermerken, dass der
Linker später da was aus einer weiteren Objektdatei oder einer Library
dazubinden muss.

von Ralf (Gast)


Lesenswert?

Hi Stefan,

danke für die Hilfe. In meinem C-Buch wird "extern" nämlich nur in
Verbindung mit dem Benkanntmachen von Variablen in anderen Modulen
verwendet, daher war ich mir unsicher, ob man es auch mit den
Prototypen bzw. Funktionen verwenden kann.

Demnach müsste "extern" mein Problem lösen können.

Gruß Ralf

von Rufus T. Firefly (Gast)


Lesenswert?

Bei Funktionsprototypen ist "extern" implizit und kann daher ohne
irgendwelche Auswirkungen weggelassen werden.

von Ralf (Gast)


Lesenswert?

Hi Rufus,

dass würde dann bedeuten, ich muss nicht die H-Datei einbinden, sondern
kann die Prototypen aus der H-Datei des externen, "fremden" Moduls
verwenden. Das ist auch nicht schlecht ;-)

Gruß Ralf

von Chris (Gast)


Lesenswert?

> dass würde dann bedeuten, ich muss nicht die H-Datei einbinden,
> sondern kann die Prototypen aus der H-Datei des externen,
> "fremden" Moduls verwenden.

Hmm, was meinst du mit letzterem?

Du weißt doch bestimmt, dass das "Einbinden" mittels #include vom
Präprozessor erledigt wird, sodass es für den Compiler absolut keine
Rolle mehr spielt, wie die Prototypen in den Code gelangt sind?

von Ralf (Gast)


Lesenswert?

Hi Chris,

eben genau das ist es ja, was ich suche. Ich wollte ja unabhängig von
dem Modul sein, in dem die externe Funktion steht. Über einen #include
bin ich jedoch immer von einem bestimmten Modul abhängig, da ich ja den
Namen der H-Datei angeben muss.

Über die Sache mit dem extern ist es egal, WO in welchem Modul die
Funktion steht.

Gruß Ralf

von Rufus T. Firefly (Gast)


Lesenswert?

Nein, es ist völlig wurscht, wie die Headerdatei heisst, in der die
Prototypen deklariert sind.
Es ist lediglich eine sinnvolle Konvention, die Headerdatei genauso
zu nennen wie das zugehörige Sourcemodul.

Daher kannst Du Dein "Treiberkonzept" beispielsweise so realisieren:

In einer Headerdatei namens "treiber.h" deklarierst Du die
Prototypen

  // treiber.h
  int machdies(char* womit);
  void machjenes(int warum);
  int machnix(void)

Und in jedem einzelnen Treibermodul implementierst Du diese Funktionen
mit exakt demselben Namen:

  // Turboblaster.c

  #include "treiber.h"

  int machdies(char* womit)
  {
    return (0);
  }

  // ... etc.


  // Gurkenhobel.c
  #include "treiber.h"

  int machdies(char* womit)
  {
    return (1);
  }

  // ... etc.


In Deiner Projektverwaltung oder Deinem Makefile darfst Du nur genau
eine der Treiberimplementierungsdateien einbinden, also entweder
turboblaster.c oder gurkenhobel.c

von Rainer Fl (Gast)


Lesenswert?

Hallo Ralf, bin grad auch dabei C für microcontroller anzuwenden. Da du
auch damit grad angefangen hast, wollt ich nachfragen ob du
Irgendwelche gute Tutorials /links zu dem Thema zusammen getragen hast.
Würde mich sehr auf eine Antwort freuen

von Ralf (Gast)


Lesenswert?

Hi Rainer,

ich suche halt immer mal wieder das Forum ab, auch das Internet bleibt
nicht verschont.

Ansonsten gucke ich auch auf www.c51.de, dort ist ebenfalls ein Forum
und Code-Beispiele gibt es dort auch. Von C51.de habe ich mir die
beiden Bücher für den Keil C51 Compiler gekauft. Und ein paar Bücher
über C allgemein habe ich auch schon.

Das ist alles was du brauchst (Aus meiner Sicht). Der Rest ist Hirn
benutzen und üben, üben, üben.

Sicher wird ein Profi vielleicht die Hände über dem Kopf
zusammenschlagen, wenn er meinen Schreib-Stil sieht, aber ES
FUNKTIONIERT grins

Wenn du ein Problem hast, kannst mir ja mailen, vielleicht kann ich dir
helfen.

Gruß Ralf

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.