使用指针调用函数,并在参数中传递可以指向函数的指针
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;
}
假设我有一个指向函数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;
}