什么是结合性?
结合性决定了当同一个表达式中出现多个相同优先级的运算符时,运算的执行顺序。
它主要解决两种问题:
左结合:从左向右计算。
右结合:从右向左计算。
左结合
大多数运算符是左结合的。这意味着运算从表达式的最左边开始。
例子:a - b - c
运算符 - 是左结合的。
它被解释为 (a - b) - c。
先计算 a - b,然后用其结果减去 c。
其他左结合运算符的例子:
a + b + c → (a + b) + c
a * b * c → (a * b) * c
a / b / c → (a / b) / c
a && b && c → (a && b) && c
右结合
少数运算符是右结合的。这意味着运算从表达式的最右边开始。
例子1:a = b = c
运算符 = 是右结合的。
它被解释为 a = (b = c)。
先执行 b = c,然后将这个赋值表达式的结果(即 c 的值)再赋给 a。
例子2:*p++
这里 * 和 ++(后缀)优先级相同,但它们是右结合的。
它被解释为 *(p++),而不是 (*p)++。先执行 p++,然后对自增前的地址解引用。
其他右结合运算符的例子:
!~a → !(~a) (一元运算符)
a ? b : c ? d : e → a ? b : (c ? d : e) (条件运算符)
结合性与优先级的关系
这是一个关键区别:
特性
优先级
结合性
解决的问题
不同运算符之间,谁先执行?
相同优先级的运算符之间,谁先执行?
类比
乘法和加法,先算乘法
多个连加的加法,从左往右算
例子
a + b * c → a + (b * c)
a + b + c → (a + b) + c
总结关系:
优先级第一:首先根据优先级确定哪些操作先绑定。
结合性第二:当优先级无法决定顺序时(即运算符相同时),再用结合性来决定。
经典示例分析
x = a + b * c > d && e || f
优先级最高:* → b * c
优先级次高:+ → a + (b * c)
优先级第三:> → (a + b * c) > d
优先级第四:&& → ((a + b * c) > d) && e
优先级第五:||(左结合) → [((a + b * c) > d) && e] || f
优先级最低:=(右结合) → x = ([((a + b * c) > d) && e] || f)
最终等价于:x = ( ( (a + (b * c)) > d ) && e ) || f )
核心要点
优先级解决“先乘除后加减”的问题。
结合性解决“多个相同运算符如何分组”的问题。
当不确定时,使用括号是确保表达式按你意图执行的最佳实践。
运算符优先级表
优先级
运算符
描述
结合性
1
::
作用域解析
从左到右
2
a++ a--
后缀自增/自减
从左到右
type() type{}
函数风格转换
从左到右
a()
函数调用
从左到右
a[]
下标
从左到右
. ->
成员访问
从左到右
3
++a --a
前缀自增/自减
从右到左
+a -a
一元正负
从右到左
! ~
逻辑非、按位非
从右到左
(type)
C风格转换
从右到左
*a
解引用
从右到左
&a
取地址
从右到左
sizeof
大小查询
从右到左
new new[] delete delete[]
动态内存
从右到左
4
.* ->*
成员指针访问
从左到右
5
* / %
乘、除、取模
从左到右
6
+ -
加、减
从左到右
7
<< >>
位左移、右移
从左到右
8
<=>
三路比较(C++20)
从左到右
9
< <= > >=
关系比较
从左到右
10
== !=
相等比较
从左到右
11
&
按位与
从左到右
12
^
按位异或
从左到右
13
|
按位或
从左到右
14
&&
逻辑与
从左到右
15
||
逻辑或
从左到右
16
?:
条件运算符
从右到左
=
赋值
从右到左
+= -= *= /= %=
复合赋值
从右到左
<<= >>=
位运算复合赋值
从右到左
&= ^= |=
位运算复合赋值
从右到左
17
,
逗号运算符
从左到右
重要说明
结合性:
大部分从左到右
一元、赋值、条件运算符从右到左
记忆技巧:
算术 > 移位 > 比较 > 位运算 > 逻辑 > 条件 > 赋值 > 逗号
一元运算符优先级很高
后缀高于前缀
最佳实践:
不确定时使用括号明确优先级
避免编写过于复杂的表达式