...复杂声明符的绑定
这是规范中的一个非常好的提示。
规则本身真的很难分析,因为它是递归的。声明和声明符的关系和部分也是相关的。
结果是:
()and[]是最里面的直接声明符部分,在左边声明(直接通过符号)函数和数组名称
*将名称声明为右侧的指针
(...) 对于...复杂的情况需要更改默认关联。
分组括号引导您从内部(标识符)到外部(左侧的类型说明符,例如“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”声明为函数数组
是的,你可以,甚至递归,但使用* 间接和括号。这样就形成了一个洋葱,中间是identifeir,左边是星星,右边是[]和()。
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)”洋葱法则
所以这个洋葱游戏会重演。[]在 和 之间由内而外()和左右左右*。语法不是问题,而是语义。