C++中&&、||、!是短路布尔逻辑运算符,分别表示“且”“或”“非”,操作布尔表达式并返回true/false;需区别于位运算符&、|、~,注意优先级、隐式转换及constexpr限制。

用 &&、||、! 做布尔逻辑运算
C++ 的逻辑与、或、非直接对应三个符号:&& 表示“且”,|| 表示“或”,! 表示“非”。它们操作的是布尔表达式,结果是 true 或 false(底层通常为 1 或 0,但语义上应视为布尔值)。
注意:这些是**逻辑运算符**,不是位运算符(&、|、~),别混用。比如 if (a & b) 是按位与,可能意外为真;而 if (a && b) 才是真正判断“a 和 b 都为真”。
-
&&是短路运算:左边为false时,右边根本不会求值(比如ptr != nullptr && ptr->valid()安全) -
||同样短路:左边为true就跳过右边 -
!优先级较高,!a && b等价于(!a) && b,但写!(a && b)时括号不能省
小心隐式转换带来的逻辑陷阱
C++ 允许整数、指针等参与逻辑运算,会自动转成布尔值:0、nullptr、空指针常量、空 std::shared_ptr 等转为 false;其余非零值/有效指针转为 true。这很方便,但也容易出错。
- 避免对浮点数直接取逻辑非:
double x = -0.0; if (!x)为true,但x == 0.0也成立——这不是 bug,但可能不符合业务意图 - 指针判空推荐写
if (ptr)或if (ptr != nullptr),别写if (!!ptr)—— 多余且易读性差 - 自定义类型若重载了
operator bool(),也要确保它只在“真正代表无效/失败”时返回false,否则if (!obj)会误导
和位运算符 &、|、~ 混用的典型错误
新手常把 && 写成 &,尤其在条件里:if (flags & FLAG_A && flags & FLAG_B) 看似想检查两个标志位都置位,但实际执行顺序是 (flags & FLAG_A) && (flags & FLAG_B) —— 因为 & 优先级低于 &&。这虽然能工作(非零即真),但可读性差,且一旦某个 FLAG_X 是 0 就崩。
- 正确做法:用位运算组合条件,如
if ((flags & (FLAG_A | FLAG_B)) == (FLAG_A | FLAG_B)) - 或者拆开写清楚:
if ((flags & FLAG_A) && (flags & FLAG_B))—— 加括号强调意图 - 绝对不要写
if (flags & FLAG_A & FLAG_B):这是按位与连算,不是逻辑“且” -
!和~完全不同:!x是布尔非(0→1,非0→0);~x是按位取反(如~1是0xFFFFFFFE)
在模板和 constexpr 中逻辑运算的限制
逻辑运算符在编译期也能用,但要注意 constexpr 上下文对操作数的要求:所有子表达式必须是常量表达式。
constexpr bool a = (2 > 1) && (3 ✅ 可行-
int x = 5; constexpr bool b = (x > 0) || false;❌x不是常量表达式,编译失败 - 模板参数推导中慎用逻辑表达式做约束,比如
requires (A::value && B::value)要确保A::value和B::value都是字面量常量类型 -
static_assert里可以用,但错误信息不显示中间值,调试困难;建议拆成多个static_assert或加注释说明条件含义
逻辑运算本身简单,但和类型转换、优先级、短路特性、编译期约束一结合,就容易掉进静默行为的坑里。最稳妥的做法是:该加括号就加,该拆条件就拆,别依赖隐式转换来“猜意图”。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











