调用void *指针指向的函数

时间:2013-09-19 16:12:16

标签: c pointers

我有一个看起来像这样的事件结构

typedef struct {
    void* fn;
    void* param;
} event;

如何通过指针调用此函数作为结构的一部分。例如,这些不起作用:

event->(*function)();
event->function();
(*event->function)();

我想知道如何使用和不使用附加的void * param进行函数调用。我最初使用此链接作为参考:

http://www.cprogramming.com/tutorial/function-pointers.html

之前我使用过这些函数指针,但是在修复语法方面遇到了麻烦。

4 个答案:

答案 0 :(得分:6)

首先需要将void*指针强制转换为函数指针:

#include <stdio.h>

typedef struct {
    void* fn;
    void* param;
} event;

void print()
{
        printf("Hello\n");
}


int main()
{
    event e;
        e.fn = print;
        ((void(*)())e.fn)();
        return 0;
}

当然,如果这真的是你想要的。如果希望结构包含指向函数的指针,而不是void*指针,请在声明中使用正确的类型:

typedef struct {
    void (*fn)();
    void* param;
} event;

在这里,您fn被声明为指向void函数的指针,param指向void*指针。

答案 1 :(得分:1)

如果我理解正确,你可能正在寻找这个:

typedef struct {
    void (*fn)();
    void (*param)();
} event;


event *E;

E->fn();
E->param();

答案 2 :(得分:0)

event类型,而不是对象或表达式。您不能访问结构类型的成员,只能访问结构类型的对象。

所以给出:

typedef struct {
    void* fn;
    void* param;
} event;

您需要拥有event类型的对象,并且需要为其成员分配值。

在您的问题中,您使用fn作为成员名称,但之后您会引用名为function的内容。我在这里假设他们应该是同一个东西,并且fn应该指向一些功能。

您无法在void*中移植函数指针。在许多(可能是大多数)实现中,您可以使用它,但语言无法保证。 (有些系统的函数指针比数据指针大,并且将函数指针转换为void*会丢失信息。)另一方面,所有指针到函数类型都可以相互转换,并且保证跳闸转换为您提供原始指针值。

我假设(我在这里做了很多假设,因为你没有提供很多信息)你希望fn指向一个带有void*参数的函数并且不会返回结果;然后让param成为void*是有道理的。为了与该假设保持一致,我们可以更改您的类型定义:

typedef struct {
    void (*fn)(void*);
    void *param;
} event;

void (*fn)(void*);语法并不完全明显。我使用cdecl来构造它。)

现在您可以定义event类型的对象:

event e = { some_func, NULL };

您必须在某处定义some_func

void some_func(void *param { /* ... */ }

或同等学历。现在,您可以通过event对象e间接调用该函数:

e.fn(e.param);

或者,如果将指针更加方便event

event *ptr = malloc(sizeof *ptr);
if (event == NULL) {
    /* error handling here */
}
ptr->fn = some_func;
ptr->param = NULL;

并且您可以在指向 - event的指针和它指向的event对象中包含的函数指针上使用间接:

ptr->fn(ptr->param);

根据您要完成的任务,您可能希望fn能够指向不同类型的函数。如果你这样做,你必须转换(使用显式强制转换)e.fnptr->fn到它通过它进行调用之前指向的函数的实际类型。你不能盲目地混合不同类型的函数指针;如果这样做,结果是编译时错误或运行时未定义的行为。您可以使用void (*)(void)(没有参数的函数指针并且不返回任何结果)作为“通用”函数指针类型,但与void*不同,您需要的所有类型的转换必须是显式的。)< / p>

  

我想知道如何使用和不使用额外的void*参数进行函数调用。

要调用不带参数的函数,只需在函数调用中使用()即可。但同样,对于给定的函数,您无法选择是否使用参数调用它;调用必须与定义匹配。 (除了printf之类的可变函数之外,你仍然需要一个正确类型的函数指针,并且不能在没有参数的情况下调用可变参数函数。)

答案 3 :(得分:0)

在没有引起未定义行为(UB)的有效C程序中,您要尝试执行的操作是不可能的。 void *可以指向有效对象,该对象可以是数组的最后一个对象之后的一个字节,也可以指向NULL,但是函数不是对象。 您可以做的是在不同的函数指针之间进行转换。 但是请记住,在调用函数指针之前,必须将函数指针转换回正确的类型。调用指向具有不同类型的函数的函数指针会导致UB。

许多嵌入式平台都有单独的函数存储,并且函数未加载到RAM中,指向void *的指针通常小于指向函数的指针。 在与Posix兼容的平台上,您可以将指针转换成void *的函数,然后再返回,而不会导致UB。但这是Posix扩展,并且是dlsym()之类的函数所必需的,它不是C的一部分。