Reputation: 682
Say that I have a pointer to function theFunc
. theFunc
takes along a pointer that can point to any function with the same parameter list as theFunc
, so the function called can set the passed pointer to NULL or a different function.
Using it would look like this:
while (funcPtr != NULL)
{
funcPtr(&funcPtr);
}
Would defining this be impossible?
Upvotes: 1
Views: 552
Reputation: 14167
Yes, it's doable.
The simple way:
void (*fptr_t)(void*);
The function pointer is data, even though it point to non-data. Therefore a pointer to function pointer can be converted to void*
without relying on compiler extensions.
This solution lacks type safety. However, it can be improved.
Currently, it is possible to declare a function taking unspecified number of parameters. It allows to form an incomplete function type. For example:
int foo();
declares a function that returns int
and takes unspecified parameters. To have a function taking no parameters use int foo(void)
.
This allows to declare a function taking a pointer to pointer to incomplete function type:
int foo(int (**)());
// call
int (*fptr)(int (**)()) = foo;
fptr(&fptr);
As mentioned in other answers typedef
-ing function types makes the code cleaner.
typedef int foo_aux_f();
typedef int foo_f(foo_aux_f**);
foo_f *fptr = &foo;
fptr(&fptr);
It is possible to improve type safety by nesting the declaration of function types deeper and deeper.
typedef int foo_aux0_f();
typedef int foo_aux1_f(foo_aux0_f**);
typedef int foo_aux2_f(foo_aux1_f**);
typedef int foo_aux3_f(foo_aux2_f**);
typedef int foo_f(foo_aux3_f**);
foo_f fptr = &foo;
fptr(&fptr);
The perfect recursive type would be reached with infinite chain of declaration but in practice 2-3 levels are sufficient.
With some abuse of the syntax of typedef
keyword it is possible to squeeze the declaration of this type:
typedef int foo_aux0_f(),
foo_aux1_f(foo_aux0_f**),
foo_aux2_f(foo_aux1_f**),
foo_aux3_f(foo_aux2_f**),
foo_f(foo_aux3_f**);
Unfortunately ... or fortunately, this trick will likely not work in upcoming C23 because the old function declarations without prototypes are planned to be removed from the language making ()
mean no arguments rather then unspecified number of argument.
Upvotes: 1
Reputation: 474
Ref your github comment, suggest you use a structure instead of type casting pointers to function pointers, etc. It's not exactly what you are requesting, but kind of. The code will then look like:
#include <stdio.h>
struct funcArgStruct
{
void (*state)(struct funcArgStruct *);
// int extra_data; // optional
};
typedef struct funcArgStruct funcArg;
void start (funcArg *ptr);
void task1 (funcArg *ptr);
void stop (funcArg *ptr);
/* Implementation of an fsm. */
int main()
{
funcArg ptr_, *ptr = &ptr_;
ptr->state = start;
// ptr->extra_data = 0; // optional
while (ptr->state != NULL)
{
ptr->state(ptr);
}
return 0;
}
void start (funcArg *ptr)
{
ptr->state = task1;
}
void stop (funcArg *ptr)
{
ptr->state = NULL;
}
void task1 (funcArg *ptr)
{
ptr->state = stop;
}
Upvotes: 1
Reputation: 68099
Yes, you can pass pointer to pointer to function. The syntax is much easier if you use typedefs.
typedef void somefunc(void);
void func1(void)
{
printf("Func1\r");
}
void func2(void)
{
printf("Func2\r");
}
void swapfunction(somefunc **ptr)
{
if(*ptr == func1) *ptr = func2;
else *ptr = func1;
}
int main(void)
{
somefunc *ptr = NULL;
swapfunction(&ptr);
ptr();
swapfunction(&ptr);
ptr();
}
You can also use function return value:
typedef void somefunc(void);
void func1(void)
{
printf("Func1\r");
}
void func2(void)
{
printf("Func2\r");
}
somefunc *swapfunction(somefunc *ptr)
{
if(!ptr) return func1;
else if (ptr == func1) return func2;
else return NULL;
}
int main(void)
{
somefunc *ptr = NULL;
while(ptr = swapfunction(ptr))
{
ptr();
}
}
Upvotes: 1
Reputation: 1835
This sort of works:
#include <stdio.h>
void *a(void)
{
printf("Calling a()\n");
return NULL;
}
void *b(void)
{
printf("Calling b()\n");
return a;
}
void *c(void)
{
printf("Calling c()\n");
return b;
}
int main(void)
{
void *(*funcPtr)(void) = &c;
while (funcPtr) {
funcPtr = funcPtr();
}
}
I don't really see good uses, especially in passing the pointer to the function itself as an argument (which I why I omitted it) but whatever floats your boat. You can of course replace the arguments to whatever you need.
You could add a typedef to help out a bit with a type:
typedef void *(*myfunc)(void);
Then you could do the following:
myfunc funcPtr = &c;
// instead of: void *(*funcPtr)(void) = &c;
I don't think any of this is particularly elegant, but it should work.
Note that it doesn't matter if you assign c
or &c
to myfunc, or whether you return a
or &a
from one of the functions.
Upvotes: 0