Quantcast
Channel: Raspberry Pi Forums
Viewing all articles
Browse latest Browse all 4151

C/C++ • Re: Understanding the Basics of Callback() and Similar Functions

$
0
0
Some detective work required. https://github.com/lbrombach/practical_ ... llback.cpp shows "<pigpiod_if2.h>"..

Code:

$ foo@pi24:~ $ apt-file search pigpiod_if2.hlibpigpiod-if-dev: /usr/include/pigpiod_if2.h
..so now off to https://github.com/joan2937/pigpio/blob ... if2.c#L410. callback() is in that header so go look at the source file..
https://github.com/joan2937/pigpio/blob ... if2.c#L410 where we see..

Code:

int callback(int pi, unsigned user_gpio, unsigned edge, CBFunc_t f)   {return intCallback(pi, user_gpio, edge, f, 0, 0);}
So go look for intCallback(). It's in the same file..

Code:

static int intCallback(   int pi, unsigned user_gpio, unsigned edge, void *f, void *user, int ex){   static int id = 0;   callback_t *p;   if ((user_gpio >=0) && (user_gpio < 32) && (edge >=0) && (edge <= 2) && f)   {      /* prevent duplicates */      p = gCallBackFirst;      while (p)      {         if ((p->pi   == pi)        &&             (p->gpio == user_gpio) &&             (p->edge == edge)      &&             (p->f    == f))         {            return pigif_duplicate_callback;         }         p = p->next;      }      p = malloc(sizeof(callback_t));      if (p)      {         if (!gCallBackFirst) gCallBackFirst = p;         p->id = id++;         p->pi = pi;         p->gpio = user_gpio;         p->edge = edge;         p->f = f;         p->user = user;         p->ex = ex;         p->next = 0;         p->prev = gCallBackLast;         if (p->prev) (p->prev)->next = p;         gCallBackLast = p;         findNotifyBits(pi);         return p->id;      }      return pigif_bad_malloc;   }   return pigif_bad_callback;}
Without looking at it in detail (you're the curious one), it's maintaining a linked list of pointers to functions. Somewhere else in the code there will be an event which triggers a call to one them when some gpio event occurs (I imagine, considering what we've seen so far). This is a C version of an interrupt handler in effect. It may in fact be one: I'm not the one who cares. ;-)

About the simplest function pointer example you can have..

Code:

#include <stdio.h>#include <stdlib.h>voidWibble(void){printf("Wibble\n");}voidWobble(void){printf("Wobble\n");}typedef void (*VCB)(void);voidCallBoth(const VCB f1, const VCB f2){ printf("CallBoth:\n"); f1(); f2();}intmain(){ void (*fcp)(void); fcp=Wibble; (*fcp)(); fcp=Wobble; fcp(); CallBoth(Wibble,Wobble); return EXIT_SUCCESS;}
Call it "c.c" say, and..

Code:

$ gcc -o c c.c && ./cWibbleWobbleCallBoth:WibbleWobble
Wibble() and Wobble() are two normal functions. In main we declare "fcp" to be a pointer to a function which takes no arguments and returns nothing. We can then set "fcp" to any "void whatever(void)" function we desire. The "(*fcp)()" is the original syntax whereas "fcp()" is the newer syntax (and a bit clearer).

CallBoth() is where things get a bit muddier. It rapidly becomes a mess. I could have defined Callback() like this..

Code:

void CallBoth(const void(*f1)(void), const void(*f2)(void))
..but that "typedef" helps a bit. We now have a VCB type which is a "void (*) (void)". Don't worry if you're lost now. C function pointer syntax is probably the hardest part of the language, eclipsed only by C++ ones which can take it to a whole new level!

You can't add a function of another kind. If we try to set "fcp" to a function with the wrong signature akin to this..

Code:

int NotHappening(const char[]);fcp=NotHappening;
..you'll get an error along these lines..

Code:

c.c: In function ‘main’:c.c:37:4: warning: assignment to ‘void (*)(void)’ from incompatible pointer type ‘int (*)(const char *)’ [-Wincompatible-pointer-types]   37 | fcp=NotHappening;
..because the compiler can't generate code to call a function via a function pointer unless the signatures match.

Look at this horrible mess. Never do this..

Code:

#include <stdio.h>#include <stdlib.h>voidWibble(void){printf("Wibble\n");}voidWobble(void){printf("Wobble\n");}voidCallBoth(const void(*f1)(void), const void(*f2)(void)){ printf("CallBoth:\n"); f1(); f2();}intNotHappening(const char s[]){ printf("NotHappening:\n"); printf("%s\n",s); printf("arrgh .. but it has!\n"); return 0;}intmain(){ void (*fcp)(void); fcp=Wibble; (*fcp)(); fcp=Wobble; fcp(); CallBoth(Wibble,Wobble); fcp=(void(*)(void))NotHappening; ((int(*)(const char[]))(*fcp))("ook"); return EXIT_SUCCESS;}
The only reason I post the above monstrosity is because, sometimes in lower level programming, things get pushed through void pointers then later coerced back into what they originally should have been. IntCallback() has a couple of void pointers.

Statistics: Posted by swampdog — Sat Sep 07, 2024 6:20 am



Viewing all articles
Browse latest Browse all 4151

Trending Articles