Forum: Compiler & IDEs Callback Funktionen und typedef


von Dario C. (dario) Benutzerseite


Lesenswert?

Werte GCC Freaks,

ich habe da mal ein Problem:

Doch zuerst die Eckdaten: AVRLIB 1.6.0 (WinAVR)

Ich habe zwei Module main.c und rtc.c

RTC hat eine Uhr und die soll zu bestimmten Zeiten eine Funktion
aus main.c aufrufen. Das habe ich wie folgt gedacht:

main.h:
1
  // Prototyp
2
  void do_action(void);
main.c:
1
 // Callback Funktion
2
 void do_action(void);
3
 {
4
     counter++;
5
 }
6
7
 // Main
8
 int main (void);
9
 {
10
     // Callback anmelden
11
     RTC_Init (do_action);
12
 }
rtc.h:
1
 // Typ der Callback Funktion
2
 typedef void (*rtc_callback_t) (void);
rtc.c:
1
 // Variable für Pointer auf die Callback Funktion
2
 rtc_callback_t RTC_DowTimerCallbackFunc;
3
4
 // Setzen der Callback Function
5
 void RTC_Init(rtc_callback_t pFunc)
6
 {
7
      RTC_CallbackFunc == pFunc;
8
      ...
9
 }
10
11
 // Aufruf irgendwo in rtc.c
12
 RTC_CallbackFunc();


Soweit so gut, was aber wenn ich der Callback Function
einen Parameter übergebn möchte, der ein typedef enum
ist, also sowas:
1
 typedef enum {
2
    MO, TU, WE, TH, FR, SA, SU, TIMER_ACTIVE
3
 } rtc_dow_t;
4
5
 RTC_CallbackFunc(rtc_dow_t dayofweek)

WO muss das typedef hin?
Es ist ja eigentlich ein Bestandteil von rtc,
hat also in main.h nix verlohren, oder?

Aber in der main.h muss der bekannt sein,
sonst gehr der Prototype nicht.

von OliverSo (Gast)


Lesenswert?

Der typedef gehört ins rtc.h, und das wiederum per #include "rtc.h" ins 
main.c.

Oliver

von Karl H. (kbuchegg)


Lesenswert?

Dario C. wrote:

>
1
>  typedef enum {
2
>     MO, TU, WE, TH, FR, SA, SU, TIMER_ACTIVE
3
>  } rtc_dow_t;
4
> 
5
>  RTC_CallbackFunc(rtc_dow_t dayofweek)
6
>
>
> WO muss das typedef hin?
> Es ist ja eigentlich ein Bestandteil von rtc,
> hat also in main.h nix verlohren, oder?

Du meinst rtc.h, nicht main.h

Doch, der muss ins rtc.h
Wie soll denn sonst die aufgerufene Funktion diesen
Parameter auswerten, wenn sie nicht weiss was ihr da
als Argument übergeben wird?

rtc.h
1
typedef enum {
2
    MO, TU, WE, TH, FR, SA, SU, TIMER_ACTIVE
3
} rtc_dow_t;
4
5
 // Typ der Callback Funktion
6
 typedef void (*rtc_callback_t) (rtc_dow_t dayOfWeek);

von Michael Wilhelm (Gast)


Lesenswert?

>// Setzen der Callback Function
> void RTC_Init(rtc_callback_t pFunc)
> {
>      RTC_CallbackFunc == pFunc;
                        ^^
>      ...
> }

ist das wirklich so gemeint?

MW

von Dario C. (dario) Benutzerseite


Lesenswert?

Karl heinz Buchegger wrote:
> rtc.h
1
 typedef enum {
2
     MO, TU, WE, TH, FR, SA, SU, TIMER_ACTIVE
3
 } rtc_dow_t;
4
 
5
  // Typ der Callback Funktion
6
  typedef void (*rtc_callback_t) (rtc_dow_t dayOfWeek);

Ja, aber die implemetierte Fuction in main.c muss ja doch so aussehen:

main.c
1
void ich_bin_die_callback_function (rtc_dow_t dayofweek)
2
{
3
  .. some code
4
}

Und der Prototyp dazu in der

main.h
1
void ich_bin_die_callback_function (rtc_dow_t);

Und jetzt muss ich ja in der main.c zuerst die rtc.h includen
und danach erst die main.h, sonst kennt die main.h den typen rtc_dow_t
ja noch nicht.

Das kann es doch nicht sein, oder?

Und in der rtc.c muss ich die main.h vor der rtc.h includen,
weil mir sonst die defines (z.B.:) F_CPU fehlen. Und spätestens
da bekomme ich Probleme.

Dario


PS:
@ Michael Wilhelm (Gast):
>> RTC_CallbackFunc == pFunc;
>                      ^^^^
> ist das wirklich so gemeint?
Tippfehler, selbstverständlich muss es heissen
1
RTC_CallbackFunc = pFunc;

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> Und der Prototyp dazu in der main.h
>
>   void ich_bin_die_callback_function (rtc_dow_t);

Was soll der da? Diese Funktion wird nur innerhalb von main.c verwendet, 
also genügt es, den Prototypen in main.c anzulegen.

Und das machst Du halt nach der üblichen #include-Orgie.

von Dario C. (dario) Benutzerseite


Lesenswert?

Das heisst:

ich packe in die Header Datei ausschließlich die Funktionen,
die von extern mit ihrem Namen aufgeruden werden müssen?

Also nicht die, die über einen Pointer aufgerufen werden,
den ich vorher übergeben habe.

Sehe ich das richtig so?

Ist die Funktion deren Pointer ich dann übergebe static?

Dario.

von OliverSo (Gast)


Angehängte Dateien:

Lesenswert?

Anbei ein Beispiel, wie du es machen könntest.

Ich würde allerdings F_CPU gar nicht im headerfile, sondern mit -DF_CPU 
im makefile als Compileroption definieren. Damit bekommmts du mehr 
Sicherheit, daß wirklich alle Dateien den selben Wert sehen.

Oliver

von Karl H. (kbuchegg)


Lesenswert?

Dario C. wrote:
> Das heisst:
>
> ich packe in die Header Datei ausschließlich die Funktionen,
> die von extern mit ihrem Namen aufgeruden werden müssen?

Richtig!

>
> Also nicht die, die über einen Pointer aufgerufen werden,
> den ich vorher übergeben habe.

Wozu soll die rtc Funktion denn den Namen der Funktion
benötigen. Sie hat ja einen Pointer darauf und macht den
Aufruf über den Pointer.

> Sehe ich das richtig so?
>
> Ist die Funktion deren Pointer ich dann übergebe static?

Nein. Das eine hat mit dem anderen nichts zu tun.

Es ist einfach so, dass die aufrufende Funktion den Namen
der Funktion gar nicht kennen braucht, weil: Sie hat ja
die Startadresse der Funktion. Und über diese Startadresse
wird die Funktion gestartet. Wie auch immer sie heissen mag.

Solange sich nur Aufrufer und aufgerufene Funktion darüber einig
sind, welche Argumente übergeben werden und welcher returntyp
zurückgegeben werden muss, ist doch alles paletti.
Und hier kommt das rtc.h Header File ins Spiel.
In diesem File ist dokumentiert wie sich der Code in rtc.c
den Aufruf so vorstellt. Die Funktion in main.c muss sich nur
an diese Vorgaben halten.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> Ist die Funktion deren Pointer ich dann übergebe static?

Ist sie zwar nicht, aber es ergäbe keinen funktionalen Unterschied, wenn 
sie es wäre.

Der einzige Unterschied zwischen einer statischen und einer 
nichtstatischen Funktion ist in C der, daß bei einer statischen Funktion 
kein für den Linker verwendbarer Symbolname erzeugt wird.
Das hat zur Folge, daß a) diese Funktion wirklich nur von Code aus dem 
die Funktion enthaltenen Modul aufgerufen werden kann und daß b) in 
anderen Modulen Funktionen mit exakt demselben Namen vorhanden sein 
können.

Der Aufruf der Funktion über einen Funktionspointer funktioniert auch 
aus anderen Modulen heraus, sofern der Wert des Funktionspointers in dem 
Modul bestimmt wird, in dem die betreffende Funktion enthalten ist.

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.