CPP运算符优先级
今天跳进了一个坑
double result = 1. + true ? 0.5 : 1.;// 输出 0.5
-
根据 运算符优先级,
算术加法
+
的优先级 高于 条件运算符?:
;所以先算
1. + true
。 -
true
会 整型提升 为1
,于是得到
1. + 1
→2.0
(double)。 -
剩下的表达式变成
2.0 ? 0.5 : 1.
-
C++ 中 任何非 0 的值在布尔上下文中都视为 true,
因此条件为真,选择
0.5
。 -
最终
result = 0.5
。
一句话总结
优先级:+
> ?:
,因此原式先算 1. + true
,结果为 0.5。
在 C++ 中,运算符的优先级(precedence)和结合性(associativity)决定了表达式在没有括号时的解析顺序。
下面给出 C++20 标准中常用的全部运算符,按照优先级从高到低排列(同一行优先级相同),并注明结合性。记住最常用的一句口诀:“单算关逻条赋逗”(单目 > 算术 > 关系 > 逻辑 > 条件 > 赋值 > 逗号),就能应付 90% 的场景。
- 作用域与字面量
运算符 | 含义 | 结合性 |
---|---|---|
:: | 全局 / 命名空间作用域 | 左→右 |
a::b | 类 / 命名空间成员 | 左→右 |
- 后缀/前缀
运算符 | 含义 | 结合性 |
---|---|---|
a++ a-- | 后缀自增 / 自减 | 左→右 |
type() type{} | 函数风格强制类型转换 | 左→右 |
a() | 函数调用 | 左→右 |
a[b] | 下标 | 左→右 |
a.b a->b | 成员访问 | 左→右 |
- 一元(单目)
运算符 | 含义 | 结合性 |
---|---|---|
++a --a | 前缀自增 / 自减 | 右→左 |
+a -a | 正 / 负号 | 右→左 |
! ~ | 逻辑非 / 按位取反 | 右→左 |
(type)a | C 风格强制类型转换 | 右→左 |
* & | 解引用 / 取地址 | 右→左 |
sizeof alignof | 长度 / 对齐 | 右→左 |
co_await | C++20 协程等待 | 右→左 |
new delete | 动态内存 | 右→左 |
- 成员指针
运算符 | 含义 | 结合性 |
---|---|---|
.* ->* | 成员指针访问 | 左→右 |
- 乘除模
运算符 | 含义 | 结合性 |
---|---|---|
* / % | 乘 / 除 / 取模 | 左→右 |
- 加减
运算符 | 含义 | 结合性 |
---|---|---|
+ - | 加 / 减 | 左→右 |
- 位移
运算符 | 含义 | 结合性 |
---|---|---|
+ - | 加 / 减 | 左→右 |
- 关系比较
运算符 | 含义 | 结合性 |
---|---|---|
< <= > >= | 小于 / 小于等于 / 大于 / 大于等于 | 左→右 |
- 相等比较
运算符 | 含义 | 结合性 |
---|---|---|
== != | 等于 / 不等于 | 左→右 |
- 按位与
运算符 | 含义 | 结合性 |
---|---|---|
& | 按位与 | 左→右 |
- 按位异或
运算符 | 含义 | 结合性 |
---|---|---|
^ | 按位异或 | 左→右 |
- 按位或
运算符 | 含义 | 结合性 | |
---|---|---|---|
` | ` | 按位或 | 左→右 |
- 逻辑与
运算符 | 含义 | 结合性 |
---|---|---|
&& | 逻辑与 | 左→右 |
- 逻辑或
运算符 | 含义 | 结合性 | ||
---|---|---|---|---|
` | ` | 逻辑或 | 左→右 |
- 三目条件
运算符 | 含义 | 结合性 |
---|---|---|
a ? b : c | 条件运算符 | 右→左 |
- 赋值与复合赋值
运算符 | 含义 | 结合性 | |
---|---|---|---|
= += -= *= /= %= &= ` | =^=<<=>>=` | 赋值与复合赋值 | 右→左 |
- 逗号
运算符 | 含义 | 结合性 |
---|---|---|
, | 逗号(顺序求值) | 左→右 |
速查口诀(从低到高记忆)
“单算关逻条赋逗”
单目 → 算术 → 关系 → 逻辑 → 条件 → 赋值 → 逗号
常见易错点
*
既可以是乘号(优先级 5)也可以是解引用(优先级 3),取决于上下文。<<
既可以是位移(优先级 7)也可以是流插入(重载为函数调用,实际表现为左→右)。&&
的优先级低于||
,因此
if (a || b && c) // 等价于 if (a || (b && c))
- 条件运算符
?:
的结合性是 右→左,因此
a ? b : c ? d : e // 等价于 a ? b : (c ? d : e)
实战示例
int x = 2, y = 3, z = 4;
int result = x + y * z; // 14, 因为 * 高于 +
result = x * y + z; // 10
result = x & y + z; // 2 & (3 + 4) = 2 & 7 = 2
result = x == y && z; // (x == y) && z → false
result = x < y ? x : y; // 2
官方参考
如需最权威、完整的列表,可直接查阅标准草案 N4860 §7.6.19(2020 草案)的表 15。