C function pointer casting to void pointer

Solution 1:

The C standard does not allow to cast function pointers to void*. You may only cast to another function pointer type. In the C11 standard, 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

Importantly, you must cast back to the original type before using the pointer to call the function (technically, to a compatible type. Definition of "compatible" at 6.2.7).

Note that the POSIX standard, which many (but not all) C compilers have to follow too because of the context in which they are used, mandates that a function pointer can be converted to void* and back. This is necessary for some system functions (e.g. dlsym).

Solution 2:

The standard unfortunately doesn't allow casting between data pointers and function pointers (because that might not make sense on some really obscure platforms), even though POSIX and others require such casts. One workaround is not to cast the pointer but to cast a pointer to the pointer (this is OK by the compiler and it will get the job done on all normal platforms).

typedef void (*FPtr)(void); // Hide the ugliness
FPtr f = someFunc;          // Function pointer to convert
void* ptr = *(void**)(&f);  // Data pointer
FPtr f2 = *(FPtr*)(&ptr);   // Function pointer restored

Solution 3:

I've got three rules of thumb when it come to data pointers and code pointers:

  • Do not mix data pointers and code pointers
  • Do not mix data pointers and code pointers
  • Do not ever mix data pointers and code pointers!

In the following function:

void setCallback(const void *fnPointer)
{
    gfnPtr = *((FN_GET_VAL*) (&fnPointer));
}

You have a data pointer that you case to a function pointer. (Not to mention that you do this by first taking the address of the pointer itself, cast it to a pointer to a pointer, before de-referencing it).

Try to rewrite it as:

void setCallback(FN_GET_VAL fnPointer)
{
     gfnPtr = fnPointer;
}

Also, you can (or should) drop the cast when setting the pointer:

main()
{
   setCallback(myfunc);
   gfnPtr();
}

As an extra bonus, you could now use the normal type checks performed by the compiler.