大家好!我是老码农。
今天分享:C 运算符优先级。
编代码时候经常会涉及复杂运算,运算符的优先级一定要记清楚,很多并不是我们认为的那样,例如:最常用的
a
a--
和a
--a
,并不是优先级一样。- 这个表也有一些规律,例如一般【与】比【或】的优先级高,例如
&
和|
&&
和||
运算符优先级列表
列表
- 从上到下依次减弱,注意【结合性】列的描述
优先级 | 运算符 | 描述 | 结合性 |
---|---|---|---|
1 | :: | 作用域解析 | 从左到右 |
2 | a a-- | 后缀自增与自减 | 从左到右 |
2 | *type*() *type*{} | 函数风格转型 | 从左到右 |
2 | a() | 函数调用 | 从左到右 |
2 | a[] | 下标 | 从左到右 |
2 | . -> | 成员访问 | 从左到右 |
3 | a --a | 前缀自增与自减 | 从右到左 |
3 | a -a | 一元加与减 | 从右到左 |
3 | ! ~ | 逻辑非和逐位非 | 从右到左 |
3 | (*type*) | C 风格转型 | 从右到左 |
3 | *a | 间接 | 从右到左 |
3 | &a | 取址 | 从右到左 |
3 | sizeof | 取大小 | 从右到左 |
3 | co_await | await 表达式 (C 20) | 从右到左 |
3 | new new[] | 动态内存分配 | 从右到左 |
3 | delete delete[] | 动态内存分配 | 从右到左 |
4 | .* ->* | 成员指针 | 从左到右 |
5 | a*b a/b a%b | 乘法、除法与余数 | 从左到右 |
6 | a b a-b | 加法与减法 | 从左到右 |
7 | << >> | 逐位左移与右移 | 从左到右 |
8 | <=> | 三路比较运算符(C 20 起) | 从左到右 |
9 | < <= | 分别为 < 与 ≤ 的关系运算符 | 从左到右 |
9 | > >= | 分别为 > 与 ≥ 的关系运算符 | 从左到右 |
10 | == != | 分别为 = 与 ≠ 的相等性运算符 | 从左到右 |
11 | & | 逐位与 | 从左到右 |
12 | ^ | 逐位异或(互斥或) | 从左到右 |
13 | ` | ` | 逐位或(可兼或) |
14 | && | 逻辑与 | 从左到右 |
15 | ` | ` | |
16 | a?b:c | 三元条件 | 从右到左 |
16 | throw | throw 运算符 | 从右到左 |
16 | co_yield | yield 表达式 (C 20) | 从右到左 |
16 | = | 直接赋值(C 类默认提供) | 从右到左 |
16 | = -= | 以和及差复合赋值 | 从右到左 |
16 | *= /= %= | 以积、商及余数复合赋值 | 从右到左 |
16 | <<= >>= | 以逐位左移及右移复合赋值 | 从右到左 |
16 | &= ^= ` | =`以逐位与、异或及或复合赋值 | 从右到左 |
17 | , | 逗号 | 从左到右 |
解读
这段摘自cppreference的解读
对于优先级不同的运算符
列于上面表中某行的运算符,将比列于低于它的行中拥有较低优先级的任何运算符,更紧密地与其实参相绑定(如同用了括号)。例如,表达式 std::cout << a & b 和 *p
会被分析为 (std::cout<< a) & b 和 *(p )
,而非 std::cout << (a & b) 或 (*p)
。
对于优先级相同的运算符
拥有相同优先级的运算符以其结合性的方向与各参数绑定。例如表达式 a = b = c 会被分析为 a = (b = c) 而非 (a = b) = c,因为赋值具有从右到左结合性,但 a b - c 会被分析为 (a b) - c 而非 a (b - c),因为加法和减法具有从左到右结合性。
对于常用的运算符
常用的运算符一定要能分清优先级,例如,经常用到
a
a--
和a
--a
&&
和||
- 还有各种位运算,位运算优先级相对较低
千万别搞混了,搞混了,运算结果肯定跟自己想像的不一样。
经验之谈
当优先级不太能确定时,可以考虑加括号,括号的优先级通常是比较高的,加括号出错的概率是比较小的。
参考文章
- C 运算符优先级
- https://zh.cppreference.com/w/cpp/language/operator_precedence