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

Posted

技术标签:

【中文标题】涉及函数指针和状态机的代码解释【英文标题】:Explanation of code involving function pointers and state machine 【发布时间】:2015-09-17 14:27:11 【问题描述】:

有人可以逐行解释吗(可能一个字符一个字符,哈哈)?

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 行的末尾有 ()。像“这就是你声明指向函数的指针的方式”这样的答案会令人满意,但是当你声明一个变量时那种类型,为什么只使用“funcptr”而不使用()?

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

第 9 行。为什么“状态”没有 ()?仍然是指向函数的指针,就像第 5 行和第 6 行的函数一样。

第 9 行。没有 () 的“开始”是什么?

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

第 17 行。为什么“state1”需要类型转换?它是已经被投射的类型。还是因为缺少 ()?

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

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

【问题讨论】:

【参考方案1】:

如问题中所述,这来自 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。这就是答案中的重点。

确实,被视为名称(不带括号),startstopstate1state3 的类型是 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 应该返回。所以,演员阵容是必要的。

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

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)(); 之类的琐事(使用此问答中的符号),并且多星也可以...

【讨论】:

@fjardon:谢谢。我也在为您的答案写评论:令人惊讶的是,我经常在一个小时后没有发布答案,然后其他人去并在其中发布答案我的几秒钟。很高兴您同意我对行号的看法——我已经解决了这个问题。 您没有义务仅仅因为还有一个答案就删除您的答案。但这是你的判断。

以上是关于涉及函数指针和状态机的代码解释的主要内容,如果未能解决你的问题,请参考以下文章

指针,数组指针,指针数组,函数指针解析

C 语言字符串拷贝 ( 函数形参使用推荐方法 | 凡是涉及 修改指针指向 的操作一律创建新的 指针变量 执行 | 引入 辅助 局部 指针变量 )

直观地解释指针及其意义?

C语言基础知识:最核心的—指针,知识总结(第一部分)

C语言中函数指针*p **p 和数组不是很明白,可以解释下麽?

C 语言字符串模型 ( strstr-while 模型 | 抽象函数模型 | 业务子函数接口定义要点 | 形参指针间接赋值 | 返回值状态 | 形参指针处理 | 形参指针判空 | 形参返回值 )(代码