...复杂声明符的绑定
这是规范中非常好的提示。
规则本身真的很难分析,因为它是递归的。 declaration 和 declarator 的关系和部分也是相关的。
结果是:
-
() 和 [] 是最里面的直接声明符部分,在左边声明(直接通过符号)函数和数组名称
-
* 将名称声明为右侧的指针
- (...) 对于...复杂的情况需要更改默认关联。
分组括号会引导您从 inside(标识符)到 outside(左侧的类型说明符,例如“int”)。
最后是指针符号* 及其所指的内容。重新制定的(括号表示可选,这里不是数组!)语法是:
declarator: [* [qual]] direct-declarator
direct-declarator: (declarator)
foo() 是 DD(直接声明符)
*foo 是一个声明符。 (“间接”演绎)
*foo() 是 *(foo())。 foo 保持一个函数, () 和 [] 绑定最强。 * 是返回类型。
(*foo)() 使 foo 成为指针。一对一功能。
顺便说一句,这也解释了为什么在声明符列表中。
int const * a, b
都是 const int,但只有 a 是指针
const 属于 int,star 只属于 a。这样就更清楚了,
const int x, *pi
但这已经是边缘混淆了。就像现代诗歌一样。适合某些场合。
即使没有括号,解析也会有轻微的掉头。但这是很自然的:
3 2 0 1
int *foo()
这种标准情况(和类似情况)必须很简单。还有著名的多维数组,如 int a[10][10][10]。
3 1 0 2
int (*foo)()
这里的括号强制“foo”是左侧的内容(指针)。
复杂的声明在 K&R C 书中有自己的章节。
这是最简单复杂的声明:
int (*(*foo)[])()
它调试到抽象类型:
int (*(*)[])()
替换(*):
int (*F[])()
缺少的数组大小会发出编译器警告 - “假设一个元素”。
作为抽象类型:
int (*[])()
但是:
int *G[]()
--> 错误:将“G”声明为函数数组
是的,你可以,甚至递归,但使用 * indirection 和括号。这样就形成了一个洋葱,中间是标识符,左边是星号,右边是 [] 和 ()。
C11 规格有这个怪物。 ... 声明可变参数:
int (*fpfi(int (*)(long), int))(int, ...)
移除所有参数:
int (*fpfi())()
只是一个返回指针的函数。一个返回 int 的函数。
但是 fpfi 的第一个参数是一个函数本身——一个指向函数的指针,返回类型和它自己的参数:
int (*)(long)
非抽象的:
int (*foo)(long)
一个指向函数的指针,该函数将 long 形式“转换”为 int。
那是参数。仅有的。返回值也是一个函数指针,指向函数的参数和返回类型在最外层。删除整个内部函数(int (*)(long), int):
int (*pfi)(int, ...)
或更通用/不完整:
int (*pfi)()
“T (D)”洋葱规则
所以这个洋葱游戏重演了。 []、() 和 * 之间的由内而外和左右左右。语法不是问题,而是语义。