Forum: Mikrocontroller und Digitale Elektronik Funktionen auslagern


von Markus (Gast)


Lesenswert?

Hallo!

Wie lagere ich denn Funktionen in Header-Dateien aus?
Muss ich die Prototypendeklaration in der Header mit den Funktionen
oder im Hauptfile angeben?

Gruß
Markus

von TOM (Gast)


Lesenswert?

Hallo Markus,

ich habe es immer folgendermasen gemacht.
Ein seperates Headerfile erstellen.
Deine Funktion z.B. "int xxx (int z,int y)" schreibst Du auch in
dieses Headerfile "extern int xxx (int,int);" somit ist diese
bekannte nun bindest Du dieses Headerfile in Deinem main Programm mit
#include <HEADERFILE.h> ein.
Nun solltest Du Deine Funktion aus main aufrufen können.

TOM

von Markus (Gast)


Lesenswert?

Hi Tom!
Muss ich im Main den Prototyp auch noch einmal deklarieren oder reicht
das im Header?
Wie mache ich es mit den Variablen und/oder LookUpTables die ich für
das Unterprogramm verwende?
Sie werden auch im Hauptprogramm verwendet.

von Karl heinz B. (heinzi)


Lesenswert?

Den Prototypen deklarierst Du im Headerfile. Und dieses
Headerfile #include -st Du dann dort wo dus brauchst, zb. im main().

Das Grundprinzip ist doch folgendes in C:

Jedes Source Code file wird fuer sich alleine vom Compiler
uebersetzt. Und in jeder dieser Source Code Einheit muss alles
deklariert sein, was der Compiler nicht von sich aus kennt.
Natuerlich kannst Du auch komplett auf den Header pfeifen und
in jedem Source Code die Dinge einzeln deklarieren. Etwa so:

File1.c
******

int foo( int bar );

void foo2()
{
  int j = foo( 5 );
}

File2.c
*******

int foo( int bar );

void foo3()
{
  int k = foo( 7 );
}

Main.c
******

int foo( int bar );
void foo2( void );
void foo3( void );

int main()
{
  int l = foo( 8 );
  foo2();
  foo3();
}

aber Du merkst schon, wo das hinfuehrt:
Wenn Du foo() anederst, zb indem ein zusatzlicher Parameter mit
aufgenommen wird, so musst Du die Aenderung in diesem Fall an
4 Stellen machen:
 1) foo selbst
 2) den Prototypen in File1.c
 3) den Prototypen in File2.c
 4) den Prototypen in Main.c

Das das bei vielen Funktionen und vielen Files mehr als
fehleranfaellig
ist, brauchen wir wohl nicht zu diskutieren.

Dazu gibt es aber in C den Mechanismus des #include

Bevor sich der Compiler den eigentlichen Programtext vornimmt, rauscht
der erstmal durch den Praeprozessor. Der ersetzt alle Zeilen mit
  #include <Dateiname>
durch den aktuellen Inhalt der Datei namens 'Dateiname'.

Du schreibst also zb.

Foo.h
*****

int foo( int bar );

File1.c
*******

#include "Foo.h"

void foo2()
{
  int j = foo( 5 );
}

File2.c
*******

#include "Foo.h"

void foo3()
{
  int k = foo( 7 );
}

Uebersetzt du zb. File1.c, dann passiert Folgendes:
Zuerst nimmt sich der Praeprozessor den Text vor und ersetzt
die Zeile
  #include "Foo.h"
mit dem Inhalt der Datei 'Foo.h'.
Als Ergebnis erhaelt er:

int foo( int Bar );

void foo2()
{
  int j = foo( 5 );
}

und erst dieses Ergebnis wird durch den tatsaechlichen C Compiler
gejagt. Der ist natuerlich happy damit, denn in der Funktion foo2()
wird eine andere Funktion foo() benutzt und deren Protoyp wurde
ja korrekt angegeben.

Aber: Aendert sich an der Funktion foo() etwas, dann aenderst Du
einfach nur an einer einzigen Stelle den Protoypen: in Foo.h
alle anderen, File1.c File2.c und Main.c  kriegen das automatisch
mit, da sie ja Foo.h inkludieren und somit die Aenderung beim
Compilieren mitkriegen.

Variablen/Lookup Tabellen.
Im Prinzip machst Du genau das gleiche, nur kommt Dir hier die
ODR (One Definition Rule) in die Quere. Jedes Teil darf nur einmal
definiert werden!
Bei einem Protoypen weiss der Compiler auch so, dass es sich um einen
Prototypen handelt. Etwas in der Form

  int foo( int bar );

kann nur ein Protoyp (also eine Deklaration) sein. Eine Definition
wuerde ganz anders aussehen

  int foo( int bar )
  {
    /* Implementierung von foo */
  }

bei globalen Variablen ist das aber anders. Ist

  int Global1;

nun eine Definition oder eine Deklaration.
Antwort: Es ist eine Definition.
Wenn Du sowas in Foo.h stehen haettest, dann wuerde der Compiler
klarerweise beim Uebersetzen von File1.c eine Variable namens
Global1 anlegen. Dasselbe wuerde er aber auch machen, wenn File2.c
und Main.c uebersetzt werden. Das geht aber nicht, denn dann wuerde
der Linker 3 Variablen namens Global1 sehen und nicht wissen, welche
denn dir Richtige ist.
Also muss man das anders machen: Die Definition muss zu einer
Deklaration werden:

Foo1.h
******

int foo( int bar );
extern int Global1;

Damit wissen alle *.c Bescheid, dass es irgendwo eine Variable namens
Global1 gibt und das diese vom Typ int ist.
Soweit so gut. Aber irgendwo muss diese Variable auch tatsaechlich
existieren, sonst koennte der Linker sie nicht finden.
Na zb. hier:

Main.c
******

#include "Foo.h"

int Global1;   /* da ist sie. Die Variable 'Global1'
                  Alle anderen die Foo.h inkludieren wissen nur
                  dass es sie gibt. Aber hier ist sie tatsaechlich */

int main()
{
  Global1 = 5;
}

von Gast (Gast)


Lesenswert?

Respekt, das ist doch mal ne Antwort!

von Markus (Gast)


Lesenswert?

@Heinzi
Supergenial! Vielen Dank!

von Marian (Gast)


Lesenswert?

Echt ne richtig schöne ausführliche Antwort, da hatte wohl schon jemand
einen zuviel getrunken und konnte sich aufgrund des Alkoholgehaltes im
Blute wohl nicht mehr zusammenreißen und musste alles schreiben was er
zu diesem Thema wusste und dann auch noch so, dass man es ohne große
Kenntnisse verstehen kann :).
Es sollte an jedem Tag Karnevalanfang sein, dann würde es hier bestimmt
öfters solche schönen ausführlichen Antworten geben...einfach klasse :)

von Hannes L. (hannes)


Lesenswert?

Schau mal in die Codesammlung. Dort gibt es einige Beiträge von Peter
Dannegger. In diesen sind meist Zip-Dateien zu finden, die komplette
Projekte enthalten. Dort kann der C-Interessierte sehen, wie man
strukturierte Programme schreibt. Dort sieht man auch, was in den
Header gehört und was in die Programmdatei. Mir persönlich ist das zwar
etwas zu hoch (ich kann kein C), aber wer C auf AVR oder 51er lernen
will, der kann sich da 'ne Menge abschaun. Ist jedenfalls besser, als
hier herumzuattern und nix zu verstehen.

Gruß und Bit- & Bytebruch...
...HanneS...

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.