I have a function that takes a string, an array of strings, and an array of pointers, and looks for the string in the array of strings, and returns the corresponding pointer from the array of pointers. Since I use this for several different things, the pointer array is declared as an array of (void *), and the caller should know what kind of pointers are actually there (and hence what kind of a pointer it gets back as the return value).
When I pass in an array of function pointers, however, I get a warning when I compile with -Wpedantic
:
clang:
test.c:40:8: warning: assigning to 'voidfunc' (aka 'void (*)(void)') from 'void *' converts between void pointer and function pointer [-Wpedantic]
gcc:
test.c:40:8: warning: ISO C forbids assignment between function pointer and ‘void *’ [-Wpedantic] fptr = find_ptr("quux", name_list, (void **)ptr_list,
Here's a test file, which despite the warning does correctly print "quux":
#include <stdio.h> #include <string.h> void foo(void) { puts("foo"); } void bar(void) { puts("bar"); } void quux(void) { puts("quux"); } typedef void (* voidfunc)(void); voidfunc ptr_list[] = {foo, bar, quux}; char *name_list[] = {"foo", "bar", "quux"}; void *find_ptr(char *name, char *names[], void *ptrs[], int length) { int i; for (i = 0; i < length; i++) { if (strcmp(name, names[i]) == 0) { return ptrs[i]; } } return NULL; } int main() { voidfunc fptr; fptr = find_ptr("quux", name_list, (void **)ptr_list, sizeof(ptr_list) / sizeof(ptr_list[0])); fptr(); return 0; }
Is there any way to fix the warning, other than not compiling with -Wpedantic
, or duplicating my find_ptr function, once for function pointers and once for non-function pointers? Is there a better way to achieve what I'm trying to do?
Any pointer to an object, optionally type-qualified, can be converted to void* , keeping the same const or volatile qualifications.
Yes, it can. This is purpose of casting function pointers, just like usual pointers. We can cast a function pointer to another function pointer type but cannot call a function using casted pointer if the function pointer is not compatible with the function to be called.
Void pointersIt is permitted to assign to a void * variable from an expression of any pointer type; conversely, a void * pointer value can be assigned to a pointer variable of any type.
What will we not do with function pointers? Explanation: As it is used to execute a block of code, So we will not allocate or deallocate memory.
You can't fix the warning. In fact, in my opinion it should be a hard error since it's illegal to cast function pointers to other pointers because there are architectures out there today where this isn't just a violation of the C standard but an actual error that will make the code not work. Compilers allow it because many architectures get away with it even though those programs will crash badly on some other architectures. But it's not just a theoretical standard violation, it's something that causes real bugs.
For example on ia64 function pointers are (or at least used to be last time I looked) actually two values, both necessary to make function calls across shared libraries or a program and a shared library. Likewise, the common practice to cast and call function pointers to functions returning a value to a pointer to a function returning void because you know you'll ignore the return value anyway is also illegal on ia64 because that can lead to trap values leaking into registers causing crashes in some unrelated piece of code many instructions later.
Don't cast function pointers. Always have them match types. This is not just standards pedantry, it's an important best practice.
One solution is to add a level of indirection. This helps with lots of things. Instead of storing a pointer to a function, store a pointer to a struct
storing a pointer to a function.
typedef struct { void (*ptr)(void); } Func; Func vf = { voidfunc }; ptrlist[123] = &vf;
etc.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With