In short, my question is: does the C standard allow for an arbitrary function pointer type similar to void *
being an arbitrary data pointer type?
It is common to define call-back function types with a void *
parameter to pass on an arbitrary data package whose format is known to the call-back function, but not to the caller.
For example:
typedef void (* EventFunctionType)(void *data);
void RegisterEventFunction(EventFunctionType function, void *data);
An "EventFunction" can then be registered with a data pointer which will be passed to the function when it is called.
Now suppose we want to pass a function pointer to the call-back. The function could have any prototype which would be known to the specific call-back function, just like the arbitrary data structure above.
A void *
cannot hold a function pointer, so which type could be used?
Note: An obvious solution to this problem would be to wrap the function pointer in a data structure with the correct function pointer type, but the question is if the function pointer could be passed on directly in a generic form which the call-back could then cast to a pointer with the correct prototype?
There are no function pointer type that works the same as/similar to to void-pointer.
But function pointers has another characteristic that can be used. It's already referenced in the answer linked in this question:
In the C11 draft standard N1570, 6.3.2.3 §8:
A pointer to a function of one type may be converted to a pointer to a function of another type and back again.
This mean that you can use any function pointer type as your "arbitrary function pointer type". It doesn't matter as long as you know how to get back to the real/original type (i.e. know the original type so that you can cast correctly).
For instance:
typedef void (*func_ptr_void)(void);
and then use func_ptr_void
as your "arbitrary function pointer type".
But notice that unlike conversion between void*
and other object pointer types, the conversion between function pointers will always require an explicit cast. The code example below shows this difference:
#include <stdio.h>
typedef void (*func_ptr_void)(void);
typedef int (*f_int)(int);
int bar(int n)
{
return n * n;
}
int test(func_ptr_void f, int y)
{
f_int fc = (f_int)f; // Explicit cast
return fc(y);
}
int foo(void* p)
{
int* pi = p; // Explicit cast not needed
return *pi;
}
int main(void)
{
int x = 42;
void* pv = &x; // Explicit cast not needed
printf("%d \n", foo(pv));
func_ptr_void fpv = (func_ptr_void)bar; // Explicit cast
printf("%d \n", test(fpv, 5));
return 0;
}