运算符的优先级和结合性不属于语言语法。对于后缀和一元运算符,如下所示:
postfix-expression:
primary-expression
postfix-expression [ expression ]
postfix-expression ( argument-expression-listopt )
postfix-expression . identifier
postfix-expression -> identifier
postfix-expression ++
postfix-expression --
( type-name ) { initializer-list }
( type-name ) { initializer-list , }
unary-expression:
postfix-expression
++ unary-expression
-- unary-expression
unary-operator cast-expression
sizeof unary-expression
sizeof ( type-name )
_Alignof ( type-name )
unary-operator: one of
& * + - ~ !
cast-expression:
unary-expression
( type-name ) cast-expression
C 2011 Online Draft,附录 A.2 阶段结构语法
那么,这如何确定优先级和关联性,为什么重要?让我们从*p++ 之类的表达式开始——我们是取消引用p++,还是递增*p?这是两个非常不同的操作,因此语法的结构很重要。让我们追溯一下:
* p ++
| | |
| primary |
| expression |
| | |
| postfix |
| expression |
| | |
| +------+-----+
| |
| postfix
| expression
| |
| unary
| expression
| |
unary cast
operator expression
| |
+---------+---------+
|
unary
expression
英文:
-
<em>unary-expression</em> 产生 <em>unary-operator cast-expression</em>
-
<em>unary-operator</em> 产生 *
-
<em>cast-expression</em> 产生 <em>unary-expression</em>
-
<em>unary-expression</em> 产生 <em>postfix-expression</em>
-
<em>postfix-expression</em> 产生 <em>postfix-expression</em> ++
-
<em>postfix-expression</em> 产生 <em>primary-expression</em>
-
<em>primary-expression</em> 产生 p
这意味着表达式*p++ 被解析为*(p++) - * 运算符将应用于p++ 的结果。
*p[i] 也是同样的事情——我们最终将取消引用 p[i] 处的指针,而不是下标 *p。
对于一个涉及关联性的稍微复杂的示例,让我们看一下成员选择运算符->,如表达式foo->bar->bletch->blurga。 -> 成员选择运算符的语法是
<em>postfix-expression</em> -> <em>identifier</em>
这告诉我们foo->bar->bletch 简化为postfix-expression,blurga 简化为identifier。因此,运算符的关联性是从右到左的,表达式解析为((foo->bar)->blurga)->bletch,而不是foo->(bar->(blurga->bletch))。
您正在查看的这些表是语法设置的摘要。语法是这样设置的,因此运算符和操作数分组有点直观。您希望像 ++foo.bar[i] 这样的表达式增加 foo.bar[i],您希望 *f() 取消引用从函数返回的指针值,等等。