表达式和声明中使用了&
,*
等符号,这是两个独特的概念。
在表达式中,符号是运算符,我们有一个明确定义的优先级和关联性表。当表达式很复杂时,我们可以使用此表对其进行分解和分析。 例如
(a + b) * ++c
问题:
在声明中,这些符号不是运算符,因此我们无法为运算符应用优先级和关联性表。 声明中的符号是否有优先级和关联性表?
或者换句话说,当一个声明变得复杂时(尝试这个int*& (*&f(int*))
),是否有一种系统的方法来分解和分析它?
密切相关的后续问题:
一些书(入门)教我们如何用typedef
:
typedef int (*tp_alias)[10]; //defines tp_alias as an pointer to an array of 10 int
本书讲授的方法:使用别名作为阅读的起点,tp_alias
是新的类型名称。向左看,它有一个*
,所以它是一个指针。然后在括号外查看:在右边,[10]
表示它是一个大小为10的数组;在左边,int
表示数组的元素是int
后续问题:
我们如何阅读其他类型的别名声明,例如using
?由于别名不再适用?例如using tp_alias = int (*)[10]
?
也许是在()
内阅读,但是有多个()
?(我没见过一个但是有可能。)
答案 0 :(得分:3)
您使用螺旋规则。
对它的一个很好的解释是here。
答案 1 :(得分:2)
表达式没有优先表!
运算符的优先级是从语法中推断出来的。例如,考虑 logical-and-expression 和 logical-or-expression 的定义:
logical-and-expression:
inclusive-or-expression
logical-and-expression && inclusive-or-expression
logical-or-expression:
logical-and-expression
logical-or-expression || logical-and-expression
现在考虑表达式a || b && c
。必须将其解析为 logical-or-expression (其中左侧是 logical-or-expression a
,右侧是逻辑和表达 b && c
)。它不能被解析为逻辑和表达式,因为如果它是,那么左侧a || b
必须是逻辑 - 和-expression 也是如此。
另一方面,在(a || b) && c
中,您无法将其解析为逻辑或表达式,因为您已经(a
作为左侧,b) && c
作为右侧,两者都不是有效的表达式。您可以将其解析为逻辑和表达式,因为与(a || b)
不同,a || b
是有效的逻辑和表达式
编译器解析代码,并构建语法树。如果根节点是 logical-or-expression ,则逻辑OR操作最后完成。如果根节点是逻辑和表达式,则逻辑AND操作最后完成。等等。
好的,这是坏消息。现在是好消息。
即使表达式中的运算符没有优先级表,但大多数情况下你可以假装它(当然它可以用括号覆盖);这就是你如何在心理上解析表达方式。因此,事实证明,声明者也是如此。没有优先级表,但您可以在精神上解析它们,就好像有。
事实上,C的设计者有足够的智慧使声明使用相同的"优先规则"作为表达。这是"声明遵循用法"规则。例如,在表达式
中(*a)[10]
我们有一个包含间接表达式的数组索引表达式,而不是反之亦然。以同样的方式,在
int (*a)[10];
我们有一个包含指针声明符的数组声明符,而不是反之亦然。 (因此,结果是指向数组的指针。)因此,如果您记住表达式[]
(数组索引)和()
(函数调用)的优先级高于*
(间接) ,您也可以将相同的顺序应用于理解声明。 (引用是一种特殊情况;很容易记住,引用在声明中具有相同的"优先级"作为指针。)