Yes, the code is fine. There's various pitfalls and conversion rules at play here:
- C splits all types in two main categories: objects and functions. A pointer to a function is a scalar type which in turn is an object. (C17 6.2.5)
void*
is the generic pointer type for pointers to object type. Any pointer to object type may be converted to/from void*
, implicitly. (C17 6.3.2.3 §1).
- No such generic pointer type exists for pointers to function type. Thus a function pointer cannot be converted to a
void*
or vice versa. (C17 6.3.2.3 §1)
- However, any function pointer type can be converted to another function pointer type and back, allowing us to use something like for example
void(*)(void)
as a generic function pointer type. As long as you don't call the function through the wrong function pointer type, it is fine. (C17 6.3.2.3 §8)
Function pointers point to functions, but they are objects in themselves, just like any pointer is. And so you can use a void*
to point at the address of a function pointer.
Therefore, using a void*
to point at a function pointer is fine. But not using it to point directly at a function. In case of void *ptr1 = array;
the array decays into a pointer to the first element, a void (**)(void)
(equivalent to voidfunc*
in your example). You may point at such a pointer to function-pointer with a void*
.
Furthermore, regarding pointer arithmetic:
- No pointer arithmetic can be performed on a
void*
. (C17 6.3.2.2) Such arithmetic is a common non-standard extension that should be avoided. Instead, use a pointer to character type.
- A pointer to character type may, as a special case, be used to iterate over any object (C17 6.2.3.3 §7). Apart from concerns regarding alignment, doing so is well-defined and does not violate "strict pointer aliasing", should you de-reference the character pointer (C17 6.5 §7).
Therefore, (char*)ptr1 + sizeof(voidfunc);
is also fine. You then convert from void*
to voidfunc*
, to voidfunc
which is the original function pointer type stored in the array.
As been noted in comments, you can improve readability of this code significantly by using a typedef
to a function type:
typedef void (voidfunc)(void);
voidfunc* array[] = {&foo, &bar}; // Step 1
void* ptr1 = array; // Step 2
void* ptr2 = (char*)ptr1 + sizeof(voidfunc*); // Step 3
voidfunc* bar_ptr = *(voidfunc**)ptr2; // Step 4