Search code examples
cpointerscastingfunction-pointersvoid-pointers

Is it possible to cast struct pointer to function pointer in c?


From here: ISO C Void * and Function Pointers, I have found a workaround to cast (void*) to function pointer:

int
main(int argc, char *argv[])
{
    ...
    void (*funcp)(void);        /* Pointer to function with no arguments */
    ...
    *(void **) (&funcp) = dlsym(libHandle, argv[2]);
}

In other words - to dereference double pointer (another level of indirection).

Now that still assumes, that the final function is of void(*)() type, but I would like to make cast available to other function "types" that can for example accepts some arguments.

Then I found another workaround how to wrap function pointer in struct Why can't I cast a function pointer to (void *)? :

typedef struct
{
   void (*ptr)(void);
} Func;

Func vf = { voidfunc };

So I would like to merge these 2 ideas and make possible to pass arbitrary function type as function pointer via struct:

#include <stdio.h>

struct s{
    int a, b;
    void (*func)();
};

typedef struct{
    int (*add)(int,int);
} Func;

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

int main(){
    Func f = {add};
    struct s foo = {.func=(void*)(&f)};
    printf("%i\n",f.add(1,2));
    printf("%i\n",foo.func(1,2));
}

Unfortunately, it gives the error:

invalid use of void expression

So the question is, how to cast back the type (void*) to (int*)(int,int) inside of the printf statement?


Solution

  • even if you change the function to return int (int (*func)();) and eventually it will compile, your code is wrong.

    Calling the function pointer is in the fact a dereferencing of this pointer.

    When you assign the function pointer with the address of the struct, calling this function will actually execute the data inside the struct - not the function referenced struct member. It of course will not be successful.

    https://godbolt.org/z/GE464T

    The following example is an UB but works on x86 & arm machines and it is only for the illustrational purposes..

    struct s{
        int a, b;
        int (**func)();
    };
    
    typedef struct{
        int (*add)(int,int);
    } Func;
    
    int add(int a, int b) { return a+b; }
    
    int main(){
        Func f = {add};
        struct s foo = {.func=(void*)(&f)};
        printf("%i\n",f.add(1,2));
        printf("%i\n",(*foo.func)(1,2));
    }
    

    https://godbolt.org/z/rKvGEG

    or if you want to use the void (**)() pointer in struct

    typedef int func();
    
    struct s{
        int a, b;
        void (**func)();
    };
    
    typedef struct{
        int (*add)(int,int);
    } Func;
    
    int add(int a, int b) { return a+b; }
    
    int main(){
        Func f = {add};
        struct s foo = {.func=(void*)(&f)};
        printf("%i\n",f.add(1,2));
        printf("%i\n",((func *)(*foo.func))(1,2));
    }
    

    https://godbolt.org/z/M9qzdf

    or

    typedef int func();
    
    struct s{
        int a, b;
        void (*func)();
    };
    
    typedef struct{
        int (*add)(int,int);
    } Func;
    
    int add(int a, int b) { return a+b; }
    
    int main(){
        Func f = {add};
        struct s foo = {.func=(void*)(&f)};
        printf("%i\n",f.add(1,2));
        printf("%i\n",(*((func **)foo.func))(1,2));
    }
    

    or without typedefs

    struct s{
        int a, b;
        void (*func)();
    };
    
    typedef struct{
        int (*add)(int,int);
    } Func;
    
    int add(int a, int b) { return a+b; }
    
    int main(){
        Func f = {add};
        struct s foo = {.func=(void*)(&f)};
        printf("%i\n",f.add(1,2));
        printf("%i\n",(*((int (**)())foo.func))(1,2));
    }
    

    https://godbolt.org/z/YG9xd7