Можно ли привести указатель структуры к указателю функции в c? - PullRequest
1 голос
/ 01 августа 2020

Отсюда: ISO C Void * и указатели функций , я нашел обходной путь для преобразования (void*) в указатель функции:

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

Другими словами - чтобы двойной указатель разыменования (другой уровень косвенности).

Теперь, когда все еще предполагается, что конечная функция имеет тип void(*)(), но я хотел бы сделать приведение доступным для других «типов» функций, которые могут, например, принимает некоторые аргументы.

Затем я нашел другой обходной путь, как обернуть указатель функции в структуру Почему я не могу преобразовать указатель функции на (void *)? :

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

Func vf = { voidfunc };

Итак, я хотел бы объединить эти две идеи и сделать возможным передавать произвольный тип функции в качестве указателя функции через структуру:

#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));
}

К сожалению, это дает ошибку:

invalid use of void expression

Итак, вопрос в том, как вернуть тип (void*) в (int*)(int,int) внутри оператора printf?

1 Ответ

1 голос
/ 01 августа 2020

, даже если вы измените функцию на return int (int (* fun c) ();) и в конечном итоге она скомпилируется, ваш код неверен.

Вызов указателя функции находится в факт разыменования этого указателя.

Когда вы назначаете указателю функции адрес структуры, вызов этой функции фактически выполнит данные внутри структуры, а не член структуры, на который ссылается функция. Это, конечно, не будет успешным.

https://godbolt.org/z/GE464T

Следующий пример представляет собой UB, но работает на машинах x86 и arm и только для иллюстративных целей ..

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

или если вы хотите использовать указатель void (**)() в структуре

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

или

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));
}

или без 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

...