我正在尝试不使用typedef
来真正理解函数指针,但是似乎无法理解。我不知道传达一个指向函数的指针需要传达什么签名。
#include <stdio.h>
void odd() { printf("odd!\n"); }
void even() { printf("even!\n"); }
void (*get_pfn(int i))()
{
return i % 2 == 0 ? &even : &odd;
}
__SIGNATURE__
{
return &get_pfn;
}
int main()
{
get_pfn_pfn()(1)();
get_pfn_pfn()(2)();
return 0;
}
要使这项工作有效,__SIGNATURE__
必须是什么?
答案 0 :(得分:21)
它必须返回一个函数指针,该函数指针需要一个int
并返回一个函数指针:
void (*(*get_pfn_pfn(void))(int))(void) {
return &get_pfn;
}
更多行:
void (*
(*
get_pfn_pfn(void) // this is our function
)(int i) // this is get_pfn(int)
)(void) // this is odd() or even()
{
return &get_pfn;
}
void
可以省略,在这种情况下,函数指针指向带有未知数量参数的函数。这不是您想要的。要声明指向不带参数的函数的函数指针,应在函数参数列表内添加void
。同样,最好将get_pfn
更改为void (*get_pfn(int i))(void)
。例如,尝试从get_pfn(1)("some arg", "some other arg");
进行呼叫。 C编译器不会发出警告,因为空()
表示 unknown 参数。要说该函数不带参数,您必须(void)
。
对于许多大括号序列,尤其是))(
,函数指针很难解析。这就是为什么许多人倾向于使用typedef作为函数指针或类型的原因:
typedef void get_pfn_func_t(void);
get_pfn_func_t *get_pfn(int i) {
return i % 2 == 0 ? &even : &odd;
}
typedef get_pfn_func_t *get_pfn_pfn_func_t(int i);
get_pfn_pfn_func_t *get_pfn_pfn(void) {
return &get_pfn;
}
答案 1 :(得分:7)
函数get_pfn
的返回类型为-
void (*) ();
所以&get_pfn
的类型是-
void (*(*)(int))()
现在,此函数返回此类型,因此其签名为-
void (*(*(foo)())(int))()
您可以通过在cdecl.org中输入
来进行验证答案 2 :(得分:6)
不带typedef
的函数指针可能很难使用。要弄清楚它们,您需要由内而外地进行工作。
因此,让我们准确地分解出我们如何得出正确的函数签名。
get_pfn_pfn
是一个功能:
get_pfn_pfn()
不使用任何参数:
get_pfn_pfn(void)
并返回一个指针:
*get_pfn_pfn(void)
功能:
(*get_pfn_pfn(void))()
哪个带有int
参数:
(*get_pfn_pfn(void))(int)
并返回一个指针:
*(*get_pfn_pfn(void))(int)
功能:
(*(*get_pfn_pfn(void))(int))()
不使用任何参数:
(*(*get_pfn_pfn(void))(int))(void)
并且不返回任何内容(即void
):
void (*(*get_pfn_pfn(void))(int))(void)
当然,使用typedef
可以大大简化这一过程。
首先,even
和odd
的类型:
typedef void (*func1)(void);
然后我们可以将其应用于get_pfn
:
func1 get_pfn(int) { ... }
然后输入此函数的类型:
typedef func1 (*func2)(int);
我们可以将其应用于get_pfn_pfn
:
func2 get_pfn_pfn(void) { ... }
答案 3 :(得分:1)
是这样的:
void (*(*get_pfn_pfn(void))(int))()