1
votes

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?

1
it will never work even if you change the pointer to compile. - 0___________
Re “I have found a workaround to cast”: Perhaps you mean you have found a workaround to convert. A cast is an operator that performs a conversion, and you do not need a workaround to cast void * to a function pointer, because you can just write the cast: void (*funcp)(void) = (void (*)(void)) dlsym(libHandle, argv[2]);. That is not defined by the C standard, but it is allowed. If you are working in an environment that supports dlsym, which is documented to return a void * that is the address of code or data, then that environment necessarily supports converting void * to… - Eric Postpischil
… a function pointer. It is implicitly part of the compiler used with that environment (although this should be stated explicitly in the documentation; leaving it implicit is sub-par engineering). Further, if a C implementation does support converting void * to a function pointer, it is going to do it through a simple cast—it is unlikely any implementation would not support that but would support it through reinterpreting the bits of the pointer as you are doing. That adds other problems with representations and aliasing. - Eric Postpischil
You can just cast the return value of dlsym into an appropriate pointer-to-function type. I don't understand what you're trying to do with the structs but it seems like an XY problem. - interjay
Re “So the question is, how to cast back the type (void*) to (int*)(int,int)? in the printf statement?”: Do not do that. There is no reason for it. To print any pointer, use %p, not %i, and convert it to void *, if it is not already. - Eric Postpischil

1 Answers

1
votes

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