C programming: void * argument is really a pointer to anything, can I pass a function pointer there
I am considering how to use it correctly void *
(I have a break with the C language). As I remember it is void *
used to pass any argument to the callback function. I know it's okay to pass something like primitive types int *
, const char *
or even a set of values ββlike struct attributes *
.
I am considering if a passable function pointer would be void *
ok.
ex.
typedef void (*callback_t)(void *);
typedef void (*my_custom_callback_t)( /* list of params */ )
void someAPIFunction( /*... */, callback_t callback, void *callback_param);
void standard_callback(void *param) {
((my_custom_callback_t) param) ( /* my params */ );
}
I believe it would be correct with these types to pass my_custom_callback as a parameter in standard_callback?
void my_custom_callback(/* list of params */) { }
someAPIFunction( /*...*/, standard_callback, my_custom_callback);
source to share
No, you cannot pass a function pointer as void *
.
6.3.2.3 Pointers
- A pointer to void can be converted to a pointer or from a pointer to any type of object. A pointer to any type of object can be converted to a pointer to void and back; the result should be compared with the original pointer.
and
- A pointer to a function of one type can be converted to a pointer to a function of another type and vice versa; the result is compared to the original pointer. If the converted pointer is used to call a function whose type is not compatible with the reference type, the behavior is undefined.
Note that the ability to mix object and function pointers is not mentioned. It might appear to work on some system, but this behavior is undefined and is not guaranteed to work.
However, you can create a wrapper object and pass its address:
struct wrapper {
my_custom_callback_t func;
};
struct wrapper my_wrapper = { my_custom_callback };
someAPIFunction( /*...*/, standard_callback, &my_wrapper);
Or just pass a pointer to a function pointer (function pointer variable - object type):
my_custom_callback_t func = my_custom_callback;
someAPIFunction( /*...*/, standard_callback, &func);
source to share
As already pointed out, this is generally not valid and you will probably get a compiler warning. This is because there are platforms where function pointers are larger than data pointers.
However, a much more common case is that the pointer dimensions are indeed equal. Interfaces for accessing shared objects like dlsym()
or GetProcAddress()
do rely on this.
So, if you are sure that all target platforms will use the same size for function pointers as they do for data pointers, you can make it explicit (so the compiler will not issue any warnings) by first casting, for example uintptr_t
. Casting to and from an integer is allowed for all types of pointers and as long as the integer is large enough to hold the pointer well-defined. uintptr_t
is guaranteed to be large enough for the data pointer, so if the function pointer is the same size, that's fine.
source to share