Search code examples
arrayscpointersfunction-pointers

How to access elements of an array of function pointers passed to a function by a void pointer?


I'm trying to pass an array of function pointers to a function by a void pointer. I cannot figure how to access the elements of the array inside the function they are passed to.

Example 1 - Pass regular array via void pointer:

#include <stdio.h>

void function(void* ptr)
{
    int* arr = ptr;

    for(int i = 0; i < 5; ++i)
    {
        printf("%d ", arr[i]);
    }
}

int main()
{
    int arr_nums[5] = { 1, 2, 3, 4, 5 };

    function((void*)arr_nums);

    return 0;
}

Output: 1 2 3 4 5

Example 2 - Pass functions via void pointer:

#include <stdio.h>

int add(int a, int b)
{
    return (a + b);
}

int sub(int a, int b)
{
    return (a - b);
}

int mult(int a, int b)
{
    return (a * b);
}

int divide(int a, int b)
{
    return (a / b);
}

int function(void *ptr)
{
    return ((int(*)(int, int))ptr)(4, 2);
}

int main()
{
    printf("%d\n, function((void*)add));
    printf("%d\n, function((void*)sub));
    printf("%d\n, function((void*)mult));
    printf("%d\n, function((void*)divide));

    return 0;
}

Output:

6
2
8
2

Example 3 - Change add, sub, mult and divide to be a function pointer array:

...

int main()
{
    int (* fp_arr[4])(int, int) = { add, sub, mult, divide };
    
    printf("%d\n", function((void*)fp_arr[0]));
    printf("%d\n", function((void*)fp_arr[1]));
    printf("%d\n", function((void*)fp_arr[2]));
    printf("%d\n", function((void*)fp_arr[3]));
    
    return 0;
}

Output:

6
2
8
2

Problem - Trying to send the whole function pointer array and access the elements inside function:

...
int function(void *ptr)
{
    return ((int(*)(int, int))ptr)(4, 2); <--- How to say something like ptr[2], would call mult
}

int main()
{
    int (* fp_arr[4])(int, int) = { add, sub, mult, divide };
    
    printf("%d\n", function((void*)fp_arr));
    
    return 0;
}

Edit: I left out some details as I was trying to only outline the problem itself, the function I am passing the function pointer array to is from a graphics library and therefore I cannot change the parameter type from void* to something else. Although I do agree with making a typedef'd alias. The library itself is LVGL, but essentially I add a callback function to an object that is triggered on an event with some user data.

i.e - lv_obj_add_event_cb(obj, callback_fn, my_event_trigger, user_data); Where user data would be my function pointer array. Later when "my_event_trigger" happens on "obj" callback_fn will be called. Inside the callback function I can access the user data through a function that returns a void pointer like so:

void callback_fn(lv_event_t* e)
{
    lv_event_get_user_data(e); // would return a pointer to my data

    // what I want would be something like
    fp_arr[state]; // where it would call a different function depending on the state of the GUI
}

Therefore unfortunately I cannot change the type from a void*, but I still don't know how to reference it in such a way that I can access the elements.


Solution

  • There is a missing * in the cast in your example, ptr is a pointer to an array of function pointers:

    int function(void *ptr)
    {
        return ((int(**)(int, int))ptr)[2](4, 2);
    }
    
    int main()
    {
        int (*fp_arr[4])(int, int) = { add, sub, mult, divide };
        
        printf("%d\n", function(fp_arr));
        
        return 0;
    }
    

    Note however that function pointers cannot be portably cast as data pointers and vice versa, so function((void *)fp_arr[0]) and function((void*)add) are not portable, as well as ((int(*)(int, int))ptr)(4, 2) in examples 2 and 3.