考虑以下 typedef:
typedef int (*f1)(float);
typedef f1 (*f2)(double);
typedef f2 (*f3)(int);
f2
是一个返回函数指针的函数。与 相同f3
,但函数的类型,即f3
返回的指针,是f2
。如何在f3
没有 typedef 的情况下定义?我知道 typedefs 是更简洁、更容易理解的定义方式f3
。但是,我的目的是更好地理解 C 语法。
考虑以下 typedef:
typedef int (*f1)(float);
typedef f1 (*f2)(double);
typedef f2 (*f3)(int);
f2
是一个返回函数指针的函数。与 相同f3
,但函数的类型,即f3
返回的指针,是f2
。如何在f3
没有 typedef 的情况下定义?我知道 typedefs 是更简洁、更容易理解的定义方式f3
。但是,我的目的是更好地理解 C 语法。
从您的声明开始f1
:
int (*f1)(float);
你想f2
成为一个返回函数的指针f1
,所以f1
在上面的声明中替换为f2
:
int (* f1 )(float);
|
+-----+-----+
| |
v v
int (*(*f2)(double))(float);
声明内容如下
f2 -- f2
*f2 -- is a pointer
(*f2)( ) -- to a function
(*f2)(double) -- taking a double parameter
*(*f2)(double) -- returning a pointer
(*(*f2)(double))( ) -- to a function
(*(*f2)(double))(float) -- taking a float parameter
int (*(*f2)(double))(float) -- returning int
您重复该过程f3
:
int (*(* f2 )(double))(float);
|
+---+----+
| |
v v
int (*(*(*f3)(int))(double))(float);
读作
f3 -- f3
*f3 -- is a pointer
(*f3)( ) -- to a function
(*f3)(int) -- taking an int parameter
*(*f3)(int) -- returning a pointer
(*(*f3)(int))( ) -- to a function
(*(*f3)(int))(double) -- taking a double parameter
*(*(*f3)(int))(double) -- returning a pointer
(*(*(*f3)(int))(double))( ) -- to a function
(*(*(*f3)(int))(double))(float) -- taking a float parameter
int (*(*(*f3)(int))(double))(float); -- returning int
在 C++ 中,模板的奇迹可以使这变得更容易一些。
#include <type_traits>
std::add_pointer<
std::add_pointer<
std::add_pointer<
int(float)
>::type(double)
>::type(int)
>::type wow;
与 typedef 相同,只是您将函数定义放在其名称的位置。
如下f2
所示:
typedef int (*(*f2)(double))(float);
你可以做f3
一个练习,因为我假设这是家庭作业;)
只是不要。可以做到,但是会很混乱。Typedef 可以方便地编写和阅读这段简短的代码。
f
不带参数并返回函数指针的函数可能int (*)(float)
类似于(未经测试):
int (*f())(float);
然后剩下的你只需要继续添加括号,直到它看起来像 lisp。
学习左右规则:
“左右”规则是解读 C 声明的完全常规规则。它在创建它们时也很有用。
使用std::function
:
typedef std::function<int(float)> f1;
typedef std::function<f1(double)> f2;
typedef std::function<f2(int)> f3;
或者
typedef std::function<std::function<std::function<int(float)>(double)>(int)> f3;
受 John Bode 回答的启发,我想以图形方式呈现它。它应该可以帮助您了解编译器如何将其转换为 AST:
我们首先 (1) 从压缩类型 f3 开始,如“typedef f2 (*f3)(int);”所示。它本身就是一个函数类型。然后在 (2) 中将其进一步解包,其中放置了封闭的花括号,实质上执行 C 语言的“is-function”CFG 生成(我假设读者对编程语言词法分析有一个基本概念)。通过查看 (3),您会看到我们已经递归执行了三次“is-function”词法分析步骤,图中的“函数”节点可以看到这三次。
在自定义符号中尝试所需(但简化)的 CFG 产品,它们看起来像......
declaration -> underlying_type:specifier sp ( func-ptr-decl | specifier )
func-ptr-decl -> '(' sp '*' sp ( func-ptr-decl | specifier ) sp ')' sp '(' sp param-list sp ')'
说明符是一个字符串,在 C 编程语言中最好解释为变量名,sp 是可选的空格字符串,param-list 被简化为(可能为空)逗号分隔的声明列表。
在 C 中,每条引入变量或参数的语句都称为声明。声明由位置/名称、数据类型和初始化程序组成。在给定的问题中,我们有类型是指向函数的声明。函数指针类型递归嵌套最多 3 次。该图以箭头指向类型的方式显示了它,这意味着它们嵌套在其他类型中。