【问题标题】:Calling function pointed by void* pointer调用由 void* 指针指向的函数
【发布时间】:2013-09-19 16:12:16
【问题描述】:

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

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

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

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

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

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

我以前使用过这些函数指针,但无法正确获取语法。

【问题讨论】:

  • 您需要先将void* 转换为函数指针。还是要声明指向什么都不返回的函数的指针?
  • 如何正确地转换成函数指针,因为在这种情况下解引用结构指针?
  • 你在类型声明中有fn,但在调用中引用function。他们应该是同一个东西吗?如果您希望 fn 保存函数指针,则需要将其声明为函数指针,而不是 void*(您可以将 void* 转换为函数指针,但不能保证工作)。此外,event 是一种类型,而不是对象或表达式;你需要有一个event 类型的对象,然后才能引用它的fn 成员。
  • That tutorial 不会尝试将函数指针存储在 void* 中。你为什么要这样做?
  • 我编辑了 OP 以使其保持一致。基本上,我需要将函数指针存储在这样的结构中,并通过指针调用函数。我不确定最好的方法,本教程也没有为我解决这个问题。

标签: c pointers


【解决方案1】:

你需要先将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* 指针。

【讨论】:

  • 谢谢!这正是我一直在寻找的。对于提问时的所有错误,我深表歉意。
  • 请注意,这在技术上是不合法的。指向对象的指针和指向函数的指针是不可转换的 (6.2.3.3(8))。您必须使用第二种形式,其中成员从一开始就是一个函数指针。
  • 这会导致 UB。您不能将函数指针存储在 void * 指针中。
【解决方案2】:

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

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


event *E;

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

【讨论】:

    【解决方案3】:

    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-&gt;fn 转换为它所指向的函数的实际类型。不能盲目混用不同类型的函数指针;如果这样做,结果要么是编译时错误,要么是运行时未定义的行为。您可以使用void (*)(void)(指向没有参数且不返回结果的函数的指针)作为“通用”函数指针类型,但与void* 不同,您需要的类型的任何转换都必须是显式的。)

    我想知道如何在使用和不使用附加 void* 参数的情况下进行函数调用。

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

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-04-19
        • 1970-01-01
        • 2013-07-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-20
        • 1970-01-01
        相关资源
        最近更新 更多