4

I have an array which looks like this:

void* functions[]; // pointer to functions, each function returns an int and has int parameters A and B

I would like to cast this into the following:

int (*F)(int a, int b) = ((CAST HERE) functions)[0];
int result = F(a, b);

I have already tried "(int (*)(int, int))" as the cast but the compiler complained I am trying to use the function pointer as an array.

gsamaras
  • 71,951
  • 46
  • 188
  • 305
Jas
  • 850
  • 7
  • 21

3 Answers3

4

It will help to use a typedef for the function type:

typedef int F_type(int, int);

Then you can write:

F_type *F = (F_type *)(functions[0]);

It would be undefined behaviour (strict aliasing violation) to try and cast functions to something else before using the index operator.

Note that it is not supported by Standard C to convert void * to be function pointers. If possible, make the array be function pointers in the first place:

F_type *functions[] = { &func1, &func2 };

NB. Some people prefer using a typedef for the function pointer type, instead of the function type. I think it makes for more readable code to avoid pointer typedefs, but I mention this so you can make sense of other suggestions.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • Good answer, but I am afraid OP doesn't want a `typedef`. – gsamaras Sep 24 '17 at 07:24
  • @gsamaras sure. I downvoted your answer as it will cause undefined behaviour . Also what is your basis for claiming OP doesn't want a typedef? – M.M Sep 24 '17 at 07:27
  • Oh really? Hmm I am not sure why, could you please explain? Ah I might be wrong, since nm told OP about the typedef, then the OP answered I cannot do that, but he was answering to mm.. Sorry! – gsamaras Sep 24 '17 at 07:30
  • @gsamaras I mentioned in my answer... it aliases `void *` as a different type, which is a strict aliasing violation (unrelated types can not be aliased in general) – M.M Sep 24 '17 at 07:31
  • 3
    I appreciate this safer approach @M.M, thank you very much for it, but the problem is that I was using a third party library for this and wanted to keep it simple. So yes I was avoiding typedefs. – Jas Sep 24 '17 at 07:34
  • This really ought to have been the accepted answer. Sometimes the only way to write reliable code is to not use the shortcuts in the other answers. – StoryTeller - Unslander Monica Sep 24 '17 at 07:35
  • @M.M thanks, I updated my answer. How does it look like now? :D – gsamaras Sep 24 '17 at 07:40
  • @Jas I would say that using a typedef is simpler than not doing so – M.M Sep 24 '17 at 07:55
2

Casting with (int (**)(int, int)) might seem to do the trick now, but it invokes Undefined Behavior!

Converting void* to function pointer is not Standard C.

Note that aliasing void* to a different type; a strict aliasing violation. Read more in What is the effect of casting a function pointer void?

Please consider using an array of function pointers from the start.

gsamaras
  • 71,951
  • 46
  • 188
  • 305
  • 2
    Aliasing and conversion are different things. Aliasing incompatible types violates the strict aliasing rule, it does not invoke a conversion. For a more stark example, compare `double d[2] = {5.0,6.0}; int x = d[0];` (conversion) versus `int y = ((int *)&d)[0];` (aliasing) – M.M Sep 24 '17 at 07:55
0

function is an array of pointers to data of type void. You want to cast it to a pointer to pointers of type int (*)(int, int) which would be int (**)(int, int), so the following works:

int (*F)(int, int) = ((int (**)(int, int)) functions)[0];

As pointed out by @M.M, the above will result in undefined behaviour. You might want to read this post and this for more on that.


Ideally, you would do something like this:

// Array of 2 pointers to functions that return int and takes 2 ints
int (*functions[2])(int, int) = {&foo, &bar};

// a pointer to function
int (*F)(int, int) = functions[0];
int r = F(3, 4);
akhilmd
  • 182
  • 1
  • 8
  • 1
    This causes undefined behaviour – M.M Sep 24 '17 at 07:24
  • I tested this and it seemed to work for my application, thank you! – Jas Sep 24 '17 at 07:34
  • @Jas - Undefined behavior doesn't mean "not work". It may "seem to work" for a long time, until it breaks for no apparent reason upon moving to a new platform. By then you'd have forgotten this post and had to do overtime to figure out where you messed up. – StoryTeller - Unslander Monica Sep 24 '17 at 07:36
  • Hmm I see, but isn't a typedef just an alias? Wouldn't the compiler treat both approaches in the same manner – Jas Sep 24 '17 at 07:40
  • 2
    @Jas - You don't have to use a typedef to follow M.M's approach. The key point is that the indexing must happen before the cast. `F = (int(*)(int, int))(functions[0]);`. But then again, an array of `void*` that holds function pointers is not something the C language standard supports. – StoryTeller - Unslander Monica Sep 24 '17 at 07:44
  • @M.M thanks for pointing that out! Learnt something new today!. I had assumed that all pointers would be the same size. – akhilmd Sep 24 '17 at 08:00
  • @derFlower even if they are, the language standard doesn't allow aliasing them. You have to use an expression that performs a conversion, e.g. in StoryTeller's suggestion the value `functions[0]` is converted to function pointer. – M.M Sep 24 '17 at 08:01