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

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

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

使用它看起来像这样:

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

定义这个不可能吗?

是的,您可以将指针传递给函数指针。如果使用 typedef,语法会简单得多。

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

你也可以使用函数return值:

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

此类作品:

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

我认为这些都不是特别优雅,但应该可以。 请注意,如果您将 c&c 分配给 myfunc,或者您是否从其中一个函数分配 return a&a 都没有关系。

是的,这是可行的。

简单的方法:

void (*fptr_t)(void*);

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

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

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

int foo();

声明了一个函数 returns int 并采用未指定的参数。要使函数不带参数,请使用 int foo(void).

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

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

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

如其他答案所述typedef-ing 函数类型使代码更清晰。

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 中可能不起作用,因为计划从语言中删除没有原型的旧函数声明,使得 () 意味着没有参数而不是未指定数量的参数参数。

参考您的 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;
}