0

Confused as to how one can access a function pointer stored in a void pointer (void *).


Let's say you have this:

void *functions[] =
{
    &sqrt,         // int ft_sqrt(int nb);
    &power,
    &logN,
    &factorial;
};

// An array of void pointers, each storing a function pointer.

If I wanted to access the sqrt function, my guess would be the following:

(int (*)(int)) functions[0](x)

But my guess is wrong:

error: called object type 'void *' is not a function or function pointer


So how would one access one of these functions ?

AymenTM
  • 529
  • 2
  • 5
  • 17
  • 1
    Why would you store function pointers in an array of pointers to void? **Especially** if you are going to try to call them. – Yunnosch Aug 29 '18 at 06:34
  • Well idk, maybe this isn't the way to do this, but i was thinking if you had functions with different return types and/or that take different arguments.. you could store them all in 1 array. – AymenTM Aug 29 '18 at 06:39
  • refer to [can void* be used to store function pointers?](https://stackoverflow.com/questions/26917194/can-void-be-used-to-store-function-pointers) – Sander De Dycker Aug 29 '18 at 06:40
  • How would you meaningfully call a function if you do not know its return type? – Yunnosch Aug 29 '18 at 06:44

2 Answers2

8

Strictly speaking, you can't. A conversion between a function pointer and a void pointer is not possible. void* was never a generic pointer type for function pointers, only for object pointers. They are not compatible types.

In practice, any pointer will very likely have the size required by the address bus of the system, so object pointers and function pointers will very likely have the same representation. Not guaranteed by the standard though, and there are some exotic systems where this equivalence doesn't hold true. So you can cast between void* and a function pointer, but what will happen is undefined behavior. You will be relying on system-specific non-standard extensions.

Slightly better would be to use a function pointer type such as void (*)(void) as the generic pointer. You can convert to/from different function pointers, what will happen is compiler-specific (implementation-defined behavior). That is, the code will still be non-portable, but at least you don't risk a program crash from invoking undefined behavior.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • Got it... and as for 'converting to/from different function pointers' that would be done in the manner that you've explained [here](https://stackoverflow.com/a/52073459/9302544). Thanks! – AymenTM Aug 29 '18 at 10:03
  • Is the opposite safe? Converting from function pointer to void* pointer? – thysultan May 18 '20 at 04:59
  • @thysultan "Between" means that both ways are invalid. If X is not compatible with Y, then Y is not compatible with X. – Lundin May 18 '20 at 07:27
5

It's a matter of operator precedence: The function call operator have higher precedence than the casting operator.

That means your expression (int (*)(int)) functions[0](x) is really equal to (int (*)(int)) (functions[0](x)).

You need to explicitly add parentheses in the correct places to cast the pointer: ((int (*)(int)) functions[0])(x).


A much better solution IMO would be to have an array of pointers to functions, so the array elements already is of the correct type:

typedef int (*function_ptr)(int);

function_ptr functions[] = { ... };

Then no casting is needed: functions[0](x).

Then you also would be safe from the issues mentioned in the answer by Lundin.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Thanks for the answers and useful tips Some programmer dude, @Lundin. It works now, at least on my system.. but will definitely be taking the portability issue into consideration and change it. – AymenTM Aug 29 '18 at 06:47