3

I've seen some examples of array of function-pointers (here, for example)

In the examples I've seen the array holds functions that have a return value of the same type (all int's, or all void's for example).

But I'm wondering can you have an array that holds function-pointers of different types?

The next code won't compile:

#include <stdio.h>

void Empty_Funcion()
{
    ;
}
int funcAdd(int a, int b){
    return a+b;
}

int main()
{
    int ret = 0;

    void *array[5] = {&Empty_Funcion, &funcAdd, &Empty_Funcion, &funcAdd, &Empty_Funcion};

    ret = (*array[1])(5,7);

    printf("%d\n", ret);

    return 0;
}

It says the problem is with the assignment ret =... "void value not ignored as it ought to be".

Community
  • 1
  • 1
Maverick Meerkat
  • 5,737
  • 3
  • 47
  • 66
  • note: converting a function pointer to and from `void *` is not supported by Standard C. Compilers may offer it as an extension. In Standard C you can cast to `void(*)()` instead, and use array type `void (*array[5])() = ...` – M.M Sep 11 '16 at 22:34

3 Answers3

2

You can do it like this:

ret = ( ( int (*)(int,int) ) array[1] )(5,7);

You need to cast to pointer to function type with the correct signature.

jamesdlin
  • 81,374
  • 13
  • 159
  • 204
Anatoly Strashkevich
  • 1,834
  • 4
  • 16
  • 32
  • Thanks! And I just tried your code with typedef to make the casting a bit more easier to read, and it also works ( i.e. typedef int (*ptrInt)(int, int); and then the casting is just (ptrInt)array[1]... ) – Maverick Meerkat Sep 11 '16 at 11:01
  • also noticed I have to change my array declaration from (*array[5])() = ... to void *array[5] = ... – Maverick Meerkat Sep 11 '16 at 11:10
  • @jamesdlin why not? – Maverick Meerkat Sep 11 '16 at 11:11
  • Sorry, ignore my previous comment. Casting a pointer-to-function to a different type of pointer-to-function *and back* is legal by 6.3.2.3/8 in the C99 standard. – jamesdlin Sep 11 '16 at 11:16
  • @DavidRefaeli Actually, the way you've updated your question now makes this not strictly legal. See the update to my answer. – jamesdlin Sep 11 '16 at 21:58
  • note that you must cast to the exact type of the original function in each case, so there's no real benefit to using an array – M.M Sep 11 '16 at 22:36
2

But I'm wondering can you have an array that holds function-pointers of different types?

As noted in Anatoly's answer, your code doesn't work because your array intends to declare contain pointers-to-functions that return void, but then you try invoking it as a pointer-to-function that returns int. These are incompatible types, so an explicit cast is required. And, as noted in section 6.3.2.3/8 of the ISO C99 standard, casting a function pointer to a different function pointer type and back again is permitted:

A pointer to a function of one type may be converted to a pointer to a function of another type and back again; the result shall compare equal to the original pointer. If a converted pointer is used to call a function whose type is not compatible with the pointed-to type, the behavior is undefined.

That said, I don't see any point to doing this. The function pointer cast is a static cast (a cast known to the compiler) and not a dynamic cast, so you must manually keep track of which elements in your array are of type void (*)() and which are of type int (*)(int, int). It'd instead be simpler to have a separate array for each function pointer type and avoid casting altogether. Doing so would be less error-prone since you would not risk invoking a function pointer as the wrong type (which would be undefined behavior).


Update: You've changed your question so that array is now an array of void* pointers. Note that although normal pointers may be freely cast to and from void*, this is not true for function pointers (although it is considered to be a common extension in many implementations).

Community
  • 1
  • 1
jamesdlin
  • 81,374
  • 13
  • 159
  • 204
  • Can you give an example of how to initialize the array of function-pointers? Because what I've tried so far failed: 1) void (*array[2])(void) = {ptrAdd, ptrEmpty}; 2) void (*array[2])(int, int) = {ptrAdd, ptrEmpty}; 3) void (*array[2])(int) = {ptrAdd, ptrEmpty}; The compiler keeps throwing error because of incompatible pointer type. I had to resort to an array of void-pointers... – Maverick Meerkat Sep 12 '16 at 08:01
  • @DavidRefaeli The whole point of your question is that you're trying to force incompatible function pointers into a single array. Consequently, you'll need explicit casts *to* the expected function pointer type (e.g. `(void (*)(void)) ptrAdd`) when assigning and to cast *back* to the original type on use. But as I (and M.M) already explained, this is a lot of extra work for zero gain. You'd be much better off declaring separate arrays and avoiding casts. – jamesdlin Sep 12 '16 at 08:56
0

Your array is not declared as an array of function pointers, it is declared as an array of pointers to void.

To declare the array as an array of function pointers you can do:

int (*)(int,int) array[5] = ...

or for clarity:

typedef int (*my_function_pointer_type)(int,int);

my_function_pointer_type array[5] = ... 

In theory, you cannot call a function which returns void and expect it to return something. This is against the C standard. In practice, if you do this you most likely get an unpredictable value, but in some cases (such as trying to return a structure) with some ABIs you can get a crash.

The best way is to match the type of your "dummy" function to the type of other functions being put into the array.

PineForestRanch
  • 473
  • 2
  • 11