使用指针调用函数,并在参数中传递可以指向函数的指针

Call a function using a pointer and pass the pointer that can point to the function along in the parameters

提问人:ADBeveridge 提问时间:5/17/2022 更新时间:5/19/2022 访问量:443

问:

假设我有一个指向函数的指针。 带一个指针,该指针可以指向与 具有相同参数列表的任何函数,因此调用的函数可以将传递的指针设置为 NULL 或其他函数。theFunctheFunctheFunc

使用它将如下所示:

while (funcPtr != NULL)
{
    funcPtr(&funcPtr);
}

定义这是不可能的吗?

C 参数传递 函数指针

评论

0赞 user3386109 5/17/2022
有可能。对于对象指针,void 指针是泛型指针类型。任何指向对象的指针都可以转换为空指针,然后再转换回来。对于函数指针,没有预定义的通用指针,但没有什么能阻止您发明自己的指针,例如 然后,只需根据需要强制转换为泛型函数指针即可。void *typedef void (*myGenericFuncPtr)(void);
0赞 jxh 5/17/2022
返回指向函数的指针和传递指向函数的指针的 out 参数从根本上是等效的。请参见:stackoverflow.com/q/50638893/315052
0赞 ADBeveridge 5/18/2022
我想做的就在这里。但是它不起作用,编译器无法取消引用 void 指针,并且我不知道正确的强制转换。

答:

1赞 0___________ 5/17/2022 #1

是的,您可以将指针传递到函数的指针。如果使用 typedefs,语法会容易得多。

typedef  void somefunc(void);

void func1(void)
{
    printf("Func1\r");
}

void func2(void)
{
    printf("Func2\r");
}

void swapfunction(somefunc **ptr)
{
    if(*ptr == func1) *ptr = func2;
    else *ptr = func1;
}

int main(void)
{
    somefunc *ptr = NULL;

    swapfunction(&ptr);
    ptr();
    swapfunction(&ptr);
    ptr();
}

您还可以使用函数返回值:

typedef  void somefunc(void);

void func1(void)
{
    printf("Func1\r");
}

void func2(void)
{
    printf("Func2\r");
}

somefunc *swapfunction(somefunc *ptr)
{
    if(!ptr) return func1;
    else if (ptr == func1) return func2;
    else return NULL;
}

int main(void)
{
    somefunc *ptr = NULL;

    while(ptr = swapfunction(ptr))
    {
        ptr();
    }
}

评论

0赞 ADBeveridge 5/18/2022
但是你想做什么ptr()ptr(&ptr);
0赞 0___________ 5/18/2022
@ADBeveridge第一个片段
0赞 Cheatah 5/17/2022 #2

这种工作方式:

#include <stdio.h>

void *a(void)
{
    printf("Calling a()\n");
    return NULL;
}

void *b(void)
{
    printf("Calling b()\n");
    return a;
}

void *c(void)
{
    printf("Calling c()\n");
    return b;
}

int main(void)
{
    void *(*funcPtr)(void) = &c;

    while (funcPtr) {
        funcPtr = funcPtr();
    }
}

我真的没有看到好的用途,尤其是在将指向函数本身的指针作为参数传递时(我为什么省略它),但无论什么让你的船漂浮。当然,您可以将参数替换为您需要的任何参数。

你可以添加一个 typedef 来对类型有所帮助:

typedef void *(*myfunc)(void);

然后,您可以执行以下操作:

myfunc funcPtr = &c;
// instead of: void *(*funcPtr)(void) = &c;

我不认为这些特别优雅,但它应该有效。 请注意,是否将 或 分配给 myfunc,或者是否返回或从其中一个函数返回都无关紧要。c&ca&a

评论

0赞 0___________ 5/17/2022
我会避免,因为它可能隐藏许多潜在的问题void *
1赞 tstanisl 5/17/2022 #3

是的,这是可行的。

简单的方法:

void (*fptr_t)(void*);

函数指针是数据,即使它指向非数据。因此,可以将指向函数指针的指针转换为,而无需依赖编译器扩展。void*

该解决方案缺乏类型安全性。但是,它可以改进。

目前,可以声明一个采用未指定数量的参数的函数。它允许形成一个不完整的函数类型。例如:

int foo();

声明一个函数,该函数返回并采用未指定的参数。要使函数不带参数,请使用 。intint foo(void)

这允许声明一个函数,该函数采用指向指向不完整函数类型的指针的指针:

int foo(int (**)());

// call
int (*fptr)(int (**)()) = foo;
fptr(&fptr);

正如其他答案中提到的,-ing 函数类型使代码更简洁。typedef

typedef int foo_aux_f();
typedef int foo_f(foo_aux_f**);

foo_f *fptr = &foo;

fptr(&fptr);

通过越来越深地嵌套函数类型的声明,可以提高类型安全性。

typedef int foo_aux0_f();
typedef int foo_aux1_f(foo_aux0_f**);
typedef int foo_aux2_f(foo_aux1_f**);
typedef int foo_aux3_f(foo_aux2_f**);
typedef int foo_f(foo_aux3_f**);

foo_f fptr = &foo;
fptr(&fptr);

完美的递归类型可以通过无限的声明链来达到,但在实践中,2-3 个级别就足够了。

通过对关键字语法的一些滥用,可以压缩这种类型的声明:typedef

typedef int foo_aux0_f(),
            foo_aux1_f(foo_aux0_f**),
            foo_aux2_f(foo_aux1_f**),
            foo_aux3_f(foo_aux2_f**),
            foo_f(foo_aux3_f**);

不幸。。。或者幸运的是,这个技巧在即将到来的 C23 中可能不起作用,因为计划从语言中删除没有原型的旧函数声明,这意味着没有参数,而不是未指定数量的参数。()

评论

0赞 ADBeveridge 5/18/2022
完美的递归类型可以通过无限的声明链来达到,但在实践中,2-3 个级别就足够了。当我尝试这个时,我陷入了困境。谢谢!
1赞 Michael Walsh Pedersen 5/18/2022 #4

引用你的 github 评论,建议你使用结构而不是类型将指针转换为函数指针等。这并不完全是您所要求的,而是有点。 然后,代码将如下所示:

#include <stdio.h>

struct funcArgStruct 
{
    void (*state)(struct funcArgStruct *);
    // int extra_data; // optional
};
typedef struct funcArgStruct funcArg;

void start (funcArg *ptr);
void task1 (funcArg *ptr);
void stop (funcArg *ptr);

/* Implementation of an fsm. */
int main()
{
    funcArg ptr_, *ptr = &ptr_; 

    ptr->state = start;
    // ptr->extra_data = 0; // optional

    while (ptr->state != NULL)
    {
        ptr->state(ptr);
    }
    return 0;
}

void start (funcArg *ptr)
{
    ptr->state = task1;
}

void stop (funcArg *ptr)
{
    ptr->state = NULL;
}

void task1 (funcArg *ptr)
{
    ptr->state = stop;
}