C++运算符优先级 #
一、优先级概述 #
运算符优先级决定了表达式中运算符的计算顺序。优先级高的运算符先计算。
1.1 基本规则 #
cpp
// 优先级高的先计算
int result = 2 + 3 * 4; // 2 + (3 * 4) = 14,不是 (2 + 3) * 4 = 20
// 使用括号改变优先级
int result2 = (2 + 3) * 4; // 20
1.2 结合性 #
当优先级相同时,结合性决定计算方向。
cpp
// 左结合:从左到右
int a = 10 - 5 - 2; // (10 - 5) - 2 = 3
// 右结合:从右到左
int b = c = d = 10; // d = 10, c = d, b = c
二、完整优先级表 #
2.1 优先级从高到低 #
| 优先级 | 运算符 | 名称 | 结合性 |
|---|---|---|---|
| 1 | :: |
作用域解析 | 左到右 |
| 2 | () [] . -> ++(后缀) --(后缀) typeid |
后缀运算符 | 左到右 |
| 3 | ++(前缀) --(前缀) +(一元) -(一元) ! ~ *(解引用) &(取地址) sizeof new delete |
一元运算符 | 右到左 |
| 4 | .* ->* |
成员指针 | 左到右 |
| 5 | * / % |
乘除 | 左到右 |
| 6 | + - |
加减 | 左到右 |
| 7 | << >> |
移位 | 左到右 |
| 8 | < <= > >= |
关系 | 左到右 |
| 9 | == != |
相等 | 左到右 |
| 10 | & |
位与 | 左到右 |
| 11 | ^ |
异或 | 左到右 |
| 12 | | |
位或 | 左到右 |
| 13 | && |
逻辑与 | 左到右 |
| 14 | || |
逻辑或 | 左到右 |
| 15 | ?: |
条件 | 右到左 |
| 16 | = += -= *= /= %= &= |= ^= <<= >>= |
赋值 | 右到左 |
| 17 | , |
逗号 | 左到右 |
2.2 记忆口诀 #
text
单目 > 算术 > 移位 > 关系 > 位运算 > 逻辑 > 条件 > 赋值 > 逗号
三、常见运算符优先级 #
3.1 算术运算符 #
cpp
int a = 2 + 3 * 4; // 14,乘法优先
int b = 10 - 4 / 2; // 8,除法优先
int c = 2 * 3 % 4; // 2,从左到右
3.2 关系与逻辑运算符 #
cpp
// 关系运算符高于逻辑运算符
bool r1 = 5 > 3 && 2 < 4; // (5 > 3) && (2 < 4) = true
// 比较运算符高于相等运算符
bool r2 = 5 > 3 == 2 < 4; // (5 > 3) == (2 < 4) = true == true = true
// 逻辑与高于逻辑或
bool r3 = true || false && false; // true || (false && false) = true
3.3 位运算与逻辑运算 #
cpp
// 位运算高于逻辑运算
bool r1 = 5 & 3 && 1; // (5 & 3) && 1 = 1 && 1 = true
// 位运算优先级:& > ^ > |
int r2 = 5 | 3 ^ 1; // 5 | (3 ^ 1) = 5 | 2 = 7
int r3 = 5 ^ 3 & 1; // 5 ^ (3 & 1) = 5 ^ 1 = 4
3.4 赋值运算符 #
cpp
// 赋值优先级很低
int x;
int y = x = 10; // y = (x = 10)
// 赋值与条件
int z = x > 5 ? 1 : 0; // z = ((x > 5) ? 1 : 0)
四、常见陷阱 #
4.1 位运算与比较 #
cpp
int x = 5;
// 错误:优先级问题
if (x & 1 == 1) { } // x & (1 == 1) = x & 1,但意图是 (x & 1) == 1
// 正确
if ((x & 1) == 1) { }
4.2 移位与加减 #
cpp
int x = 1;
// 错误
int a = x << 2 + 1; // x << (2 + 1) = 8,不是 (x << 2) + 1 = 5
// 正确
int b = (x << 2) + 1; // 5
4.3 条件运算符 #
cpp
int x = 5, y = 10;
// 错误
int a = x > y ? x++ : y++; // 正确,但可能不是预期
// 复杂条件
int b = x > 0 ? x > y ? x : y : 0; // 难以理解
// 更清晰的写法
int b = (x > 0) ? ((x > y) ? x : y) : 0;
4.4 指针与自增 #
cpp
int arr[] = {10, 20, 30};
int* p = arr;
// 优先级:后缀++高于*
int a = *p++; // a = arr[0] = 10, p指向arr[1]
int b = *++p; // p指向arr[2], b = arr[2] = 30
int c = ++*p; // arr[2] = 31, c = 31
int d = (*p)++; // d = 31, arr[2] = 32
五、使用括号的建议 #
5.1 何时使用括号 #
cpp
// 1. 不确定优先级时
int result = (a & b) | (c & d);
// 2. 复杂表达式
int value = ((a + b) * c - d) / e;
// 3. 位运算与比较
if ((flags & MASK) == VALUE) { }
// 4. 移位运算
int shifted = (value << shift) + offset;
5.2 不需要括号的情况 #
cpp
// 算术运算:遵循数学习惯
int area = width * height;
int perimeter = 2 * (width + height);
// 简单比较
if (x > 0 && y > 0) { }
// 简单赋值
x = y + z;
六、求值顺序 #
6.1 未定义的求值顺序 #
cpp
int i = 0;
int arr[] = {0, 0, 0};
// 未定义行为:i的自增顺序未定义
arr[i++] = i; // 未定义!
// 更复杂的例子
int f();
int g();
int result = f() + g(); // f()和g()的调用顺序未定义
6.2 C++17的求值顺序改进 #
cpp
// C++17:函数参数求值顺序未定义
func(a(), b()); // a()和b()的顺序未定义
// C++17:赋值右侧先于左侧求值
int arr[10];
int i = 0;
arr[i++] = i; // C++17:arr[0] = 1(定义行为)
6.3 序列点 #
cpp
// 序列点确保求值顺序
int x = 0;
int y = (x++, x++); // 未定义行为(C++17前)
// 使用分号分隔
x++;
x++;
int y = x;
七、运算符重载与优先级 #
7.1 优先级不可改变 #
cpp
class Complex {
public:
Complex operator+(const Complex& other);
Complex operator*(const Complex& other);
};
Complex a, b, c;
Complex result = a + b * c; // 仍然是 a + (b * c)
7.2 结合性不可改变 #
cpp
Complex a, b, c;
Complex result = a - b - c; // (a - b) - c
八、实际示例 #
8.1 复杂表达式分析 #
cpp
int a = 2, b = 3, c = 4, d = 5;
int result = a + b * c - d / a << 1;
// 分析步骤:
// 1. b * c = 12
// 2. d / a = 2
// 3. a + 12 = 14
// 4. 14 - 2 = 12
// 5. 12 << 1 = 24
// 使用括号更清晰
int result = (((a + (b * c)) - (d / a)) << 1);
8.2 条件表达式 #
cpp
int score = 85;
char grade;
grade = score >= 90 ? 'A' :
score >= 80 ? 'B' :
score >= 70 ? 'C' :
score >= 60 ? 'D' : 'F';
// 等价于
if (score >= 90) grade = 'A';
else if (score >= 80) grade = 'B';
else if (score >= 70) grade = 'C';
else if (score >= 60) grade = 'D';
else grade = 'F';
8.3 指针操作 #
cpp
int arr[] = {10, 20, 30, 40, 50};
int* p = arr;
// 分析以下表达式
int x = *p++; // x = 10, p指向arr[1]
int y = *++p; // p指向arr[2], y = 30
int z = ++*p; // arr[2] = 31, z = 31
int w = (*p)++; // w = 31, arr[2] = 32
九、最佳实践 #
9.1 使用括号明确意图 #
cpp
// 不推荐
if (x & MASK == VALUE)
// 推荐
if ((x & MASK) == VALUE)
9.2 分解复杂表达式 #
cpp
// 不推荐
int result = a + b * c - d / e << f & g | h;
// 推荐
int temp1 = b * c;
int temp2 = d / e;
int temp3 = a + temp1 - temp2;
int result = ((temp3 << f) & g) | h;
9.3 避免依赖求值顺序 #
cpp
// 不推荐
int x = f() + g() * h();
// 推荐
int temp1 = g();
int temp2 = h();
int temp3 = f();
int x = temp3 + temp1 * temp2;
9.4 使用constexpr表达式 #
cpp
constexpr int calculate(int a, int b, int c) {
return a + b * c;
}
constexpr int result = calculate(2, 3, 4); // 编译期计算
十、总结 #
优先级速查 #
| 类型 | 运算符 | 优先级 |
|---|---|---|
| 最高 | :: () [] . -> |
高 |
| 一元 | ++ -- ! ~ * & |
|
| 算术 | * / % > + - |
|
| 移位 | << >> |
|
| 关系 | < <= > >= > == != |
|
| 位运算 | & > ^ > | |
|
| 逻辑 | && > || |
|
| 条件 | ?: |
|
| 赋值 | = += 等 |
|
| 最低 | , |
低 |
记住几点 #
- 使用括号明确意图
- 不确定时查表或使用括号
- 避免过于复杂的表达式
- 注意求值顺序问题
下一步,让我们学习控制流!
最后更新:2026-03-26