Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I cast a function pointer to (void *)?

Tags:

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?

like image 252
sagittarian Avatar asked Apr 15 '16 11:04

sagittarian


People also ask

Can you cast any pointer to a void pointer?

Any pointer to an object, optionally type-qualified, can be converted to void* , keeping the same const or volatile qualifications.

Can you cast a function pointer?

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.

Can pointer be assigned to void?

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 Cannot be done with function pointer?

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.


2 Answers

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.

like image 136
Art Avatar answered Sep 18 '22 15:09

Art


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.

like image 43
n. 1.8e9-where's-my-share m. Avatar answered Sep 20 '22 15:09

n. 1.8e9-where's-my-share m.