1

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?

milanHrabos
  • 2,010
  • 3
  • 11
  • 45
  • it will never work even if you change the pointer to compile. – 0___________ Aug 01 '20 at 15:25
  • 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 Aug 01 '20 at 15:31
  • … 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 Aug 01 '20 at 15:31
  • 1
    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](http://xyproblem.info/). – interjay Aug 01 '20 at 15:32
  • 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 Aug 01 '20 at 15:35
  • @EricPostpischil it cannot be called as in the OP question. Here we have two levels on indirection. – 0___________ Aug 01 '20 at 15:37
  • @P__J__: My comment says nothing about calling “as in the OP question.” – Eric Postpischil Aug 01 '20 at 15:37
  • @EricPostpischil function to return something has to be called first. Or maybe I am wrong – 0___________ Aug 01 '20 at 15:40
  • @P__J__: So? Call the function. Use a function pointer. Get the function pointer by using a cast on a `void *` if needed, as I wrote in my comment. None of that has anything to do with calling a function “as in the OP question,” that is, by using any sort of structure or address of a structure. – Eric Postpischil Aug 01 '20 at 15:46
  • @EricPostpischil he is assigning the function pointer with reference to struct. He will call the struct not the function which is referenced by the function pointer in the struct. ttps://godbolt.org/z/GE464T. He needs 2 levels of indirection (I am abstracting from the UB) – 0___________ Aug 01 '20 at 15:52
  • All options in my answer – 0___________ Aug 01 '20 at 16:00

1 Answers1

1

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

0___________
  • 60,014
  • 4
  • 34
  • 74