如问题中所述,这来自 C 常见问题解答网站。问题是:
问:如何声明一个可以返回指向相同类型函数的指针的函数?我正在构建一个状态机,每个状态都有一个函数,每个函数都返回一个指向下一个状态函数的指针。但是我找不到声明函数的方法——我似乎需要一个函数返回指向函数的指针,返回指向函数的指针,返回指向函数的指针……,无穷无尽。
A:你不能直接做到这一点。一种方法是让函数返回一个通用函数指针(参见问题 4.13),并在传递指针时进行一些明智的强制转换来调整类型:
然后是使用 SO 问题中显示的代码的第一个示例。
正如常见问题解答中所说,您无法创建返回指向其自身函数类型的指针的函数,因此您必须使编译器正常工作。
第 1 行:typedef int (*funcptr)();
这在末尾有(),因为没有它们,您将拥有typedef int (*intptr); 或typedef int *intptr;,这不是您想要的。空括号是一个不确定的——不是空的——参数列表。 是你声明函数指针的方式——在尝试使用我的默认编译选项进行编译之前,我将代码修改为:typedef int (*funcptr)(void);。
因此,funcptr 是一个指向返回 int 的函数的指针,并且(至少出于本次讨论的目的)不接受任何参数。
第 2 行:typedef funcptr (*ptrfuncptr)();
不要在没有中间类型的情况下尝试这个!这也是一个指向函数的指针,该函数返回一个 funcptr — 我使用 typedef funcptr (*ptrfuncptr)(void); 断言“并且不接受任何参数”。
第 4 行和第 5 行:funcptr start(), stop(); 等
这些行声明了一组 5 个函数。同样,参数列表是未指定的——所以我将它们视为具有(void)。这些函数返回一个funcptr。但是,他们自己的类型不是funcptr。这就是答案中的重点。
确实,被视为名称(不带括号),start、stop 和 state1 到 state3 的类型是 ptrfuncptr — 指向返回 funcptr 的函数的指针。
第 9 行:ptrfuncptr state = start;
变量state 的类型为ptrfuncptr,并被初始化(无需强制转换)以指向函数start。请注意,这不会调用该函数;它只是初始化一个变量,就像你有int i = -37;一样,它会将int类型的变量i初始化为值-37。
第 12 行:state = (ptrfuncptr)(*state)();
是时候拿出大棒了。这一行包含一个函数调用和一个强制转换。
函数指针背后的原始逻辑是“类型模仿使用”概念。例如,如果您有:
int *p;
那么在表达式中,*p 的类型为 int。使用函数指针,您可以:
int (*intfuncptr)();
在一个表达式中,(*intfuncptr)() 代表一个int;这是调用intptrfunc 指向的函数的结果。在准标准 C 中,(*pointer_to_function)() 表示法是使用函数指针的唯一方法。标准 C 允许您省略指针周围的 (* 和 )。
因此,在现代符号中,state = (ptrfuncptr)(*state)(); 行也可以写成state = (ptrfuncptr)state();。当我学习 C 时,这不是一个选项,所以我仍然更喜欢明确的“这是通过指向函数的指针调用函数”表示法。常见问题解答确实提到了这一点。
因此,该行调用state 指向的函数,并捕获state 中的返回值。但是函数返回的值是funcptr,而不是ptrfuncptr,所以我们需要让编译器接受我们对自己所做的事情的了解足以保持沉默。所以,(ptrfuncptr) 演员就是这样做的。
第 17 行:return (funcptr)state1;
由于start 返回一个funcptr,但state1 是一个指向返回funcptr 的函数的指针,这里的强制转换再一次迫使编译器接受类型不匹配是必要的。后面没有括号,state1 只是函数的名称,而不是函数的调用,因此具有 ptrfuncptr 类型 — 指向返回 funcptr 的函数的指针,而不仅仅是 funcptr 这是什么start 应该返回。所以,演员阵容是必要的。
有关更多令人兴奋的函数指针,请参阅:
...某处有一个问题讨论诸如state = (ptrfuncptr)(******state)(); 之类的琐事(使用此问答中的符号),并且多星也可以...