1. 常见运算符和结合律
结合律 | 运算符 | 功能 | 语法 |
---|---|---|---|
右 | ! | 逻辑非 | !expr |
左 | < | 小于 | a < b |
左 | <= | 小于等于 | a <= b |
左 | > | 大于 | a > b |
左 | >= | 大于等于 | a >= b |
左 | == | 相等 | a == b |
左 | != | 不相等 | a != b |
左 | && | 逻辑与 | cond1 && cond2 |
左 | || | 逻辑或 | cond1 || cond2 |
- 优先级:所有关系运算符优先级高于逻辑运算符;逻辑非最高,逻辑与次之,逻辑或最低。
- 结合律:均为左结合,遇到多重同级时从左向右处理。
2. 真值与隐式转换
-
算术值 / 指针
0
或nullptr
→ 假 (false
)- 其他数值或非空指针 → 真 (
true
)
-
非布尔类型
C++ 会先将操作数 转换到布尔类型,再做逻辑判断。例如:int x = 42; if (x) // true,因为 x != 0 if (!x) // false
Tip:不要写
if (x == true)
,那是在把true
转换成1
再和x
比较——意图不清,也往往是多余的。
3. 关系运算符:直观的大小比较
- 等价比较:
==
,!=
- 大小比较:
<
,<=
,>
,>=
可以作用于:
- 算术类型(整数、浮点)
- 指针(同一数组/同一对象范围内的比较)
int a = 5, b = 10;
if (a < b) std::cout << "a < b\n";
if (ptr1 != ptr2) // 比较两个指针地址
警惕:连写
a < b < c
不是 数学上的“三元不等式”——实际是先a < b
(返回0/1
),再与c
比较!正确写法:if (a < b && b < c) { /* ... */ }
4. 短路求值:效率与安全并重
- 逻辑与
&&
- 先 计算左侧
- 只有 左侧为
true
时,才计算右侧
- 逻辑或
||
- 先 计算左侧
- 只有 左侧为
false
时,才计算右侧
这种行为称为 短路求值,既可提升效率,也能保障安全。例如:
std::string s = /* ... */;
size_t i = /* ... */;
if (i < s.size() && !std::isspace(s[i])) {
// 确保 i 合法后,才访问 s[i]
}
5. 当心副作用
避免在同一表达式里“读写同对象”,否则求值顺序不定,后果难以预测:
int x = 0;
// UB! 同一表达式中 x 被多次修改/读取,没有顺序保证
if (x++ && x) { /* ... */ }
6. 小结
- 了解优先级:
!
> 关系运算 >&&
>||
- 用短路守护:先判断再访问,避免越界或空指针。
- 清晰意图:不要写
== true/false
,直接用if (cond)
或if (!cond)
。 - 谨慎副作用:别在条件表达式里既修改又读取同一变量。
掌握这些逻辑与关系运算符的实战技巧,你的分支判断将更加健壮且高效。试着在下一次代码审查中,善用短路求值和清晰的对比写法,减少隐藏的 bug 吧!