涉及函数指针和状态机的代码解释

Explanation of code involving function pointers and state machine

谁能逐行解释一下(也许是逐字解释,哈哈)?

typedef int (*funcptr)();     /* generic function pointer */
typedef funcptr (*ptrfuncptr)();  /* ptr to fcn returning g.f.p. */

funcptr start(), stop();
funcptr state1(), state2(), state3();

void statemachine()
{
    ptrfuncptr state = start;

    while(state != stop)
        state = (ptrfuncptr)(*state)();
}

funcptr start()
{
    return (funcptr)state1;
}  

例如,我想知道为什么第1行的末尾有()。像"that's just how you declare a pointer to a function"这样的答案会令人满意,但是当您声明该类型的变量时,为什么只使用不带 ()?

的 "funcptr"

第 4 行和第 5 行。为什么这里有 ()?这些不是函数,它们是指向函数的指针,对吧?

第 9 行。为什么 "state" 没有 ()?仍然是第 5 行和第 6 行中指向函数的指针。

第 9 行。没有 () 的 "start" 是什么?

第 12 行。什么?! (我知道什么是类型转换。至少我认为我知道...)

第 17 行。为什么 "state1" 需要类型转换?它属于已经被铸造的类型。还是因为它缺少 ()?

这对我理解这些概念很有帮助。

PS。这是我将在我正在设计的电子虚拟负载中使用的微控制器。觉得是学习C的好机会,代码来自http://c-faq.com/decl/recurfuncp.html

如问题中所述,这来自 C FAQs 网站。问题是:

Q: How can I declare a function that can return a pointer to a function of the same type? I'm building a state machine with one function for each state, each of which returns a pointer to the function for the next state. But I can't find a way to declare the functions—I seem to need a function returning a pointer to a function returning a pointer to a function returning a pointer to a function…, ad infinitum.

A: You can't quite do it directly. One way is to have the function return a generic function pointer (see question 4.13), with some judicious casts to adjust the types as the pointers are passed around:

然后是使用 SO 问题中显示的代码的第一个示例。

正如常见问题解答所说,您不能创建一个 return 指向其自身类型函数的指针的函数,因此您必须强行让编译器工作。

第 1 行:typedef int (*funcptr)();

最后有 (),因为如果没有它们,您将得到 typedef int (*intptr);typedef int *intptr;,这不是您想要的。空括号是不确定的——不是空的——参数列表。它 声明函数指针的方式 — 在尝试使用我的默认编译选项进行编译之前,我将代码修改为:typedef int (*funcptr)(void);.

因此,

A funcptr 是一个指向函数的指针,该函数 return 是一个 int 并且(至少出于本次讨论的目的)不接受任何参数。

第 2 行:typedef funcptr (*ptrfuncptr)();

没有中间类型就不要尝试这个!这也是一个指向函数的指针,函数 return 是一个 funcptr — 我使用 typedef funcptr (*ptrfuncptr)(void); 断言 'and takes no arguments'.

第 4 和第 5 行:funcptr start(), stop();

这些行声明了一组 5 个函数。同样,参数列表是未指定的——所以我将把它们视为具有 (void)。这些函数return一个funcptr。但是,自己的类型不是funcptr。这就是答案中提出的观点。

确实,作为名称(不带括号),startstopstate1state3 的类型是 ptrfuncptr — 指向函数 returning a funcptr.

的指针

第 9 行:ptrfuncptr state = start;

变量 state 的类型为 ptrfuncptr,并被初始化(无需转换)以指向函数 start。请注意,这不会调用该函数;它只是初始化一个变量,就像你有 int i = -37; 一样,它将类型 int 的变量 i 初始化为值 -37.

第 12 行:state = (ptrfuncptr)(*state)();

是时候拿出大棒了。此行包含一个函数调用和一个转换。

函数指针背后的原始逻辑是 'type mimics use' 概念。例如,如果您有:

int *p;

然后在表达式中,*p 的类型为 int。使用函数指针,您有:

int (*intfuncptr)();

并且在一个表达式中,(*intfuncptr)()代表一个int;它是调用intptrfunc指向的函数的结果。在准标准 C 中,(*pointer_to_function)() 表示法是使用指向函数的指针的唯一方法。标准 C 允许您省略指针周围的 (*)

因此,在现代符号中,行 state = (ptrfuncptr)(*state)(); 也可以写成 state = (ptrfuncptr)state();。当我学习 C 时,这不是一个选项,所以我仍然更喜欢显式 'this is invoking a function via a pointer to function' 表示法。常见问题解答确实提到了这一点。

因此,该行调用state指向的函数,并捕获state中的return值。但是由函数编辑的值 return 是 funcptr,而不是 ptrfuncptr,因此我们需要让编译器接受我们对正在做的事情足够了解以保持沉默.所以,(ptrfuncptr)演员就是这样做的。

第 17 行:return (funcptr)state1;

由于 start return 是 funcptr,但是 state1 是指向 return 是 funcptr 的函数的指针,因此强制转换这里,再一次,有必要使编译器接受类型不匹配。如果后面没有括号,state1 只是函数的名称,而不是函数的调用,因此具有类型 ptrfuncptr — 指向函数 returning a funcptr,而不仅仅是 funcptrstart 应该是 return。所以,强制转换是必要的。

有关更多令人兴奋的函数指针,请参阅:

  • Understanding typedefs for function pointer in C — examples, hint and tips, please
  • How typedef works for function pointers
  • Is it a good idea to typedefpointers? — 一般答案,不,但是函数指针有一个强烈的例外。
  • What are the various styles of defining a function returning a function pointer?

…某处有一个讨论琐事的问题,如 state = (ptrfuncptr)(******state)();(使用此问答中的符号),多星也有效…