条件语句

建议先阅读:06_运算符与表达式

原理

程序计数器与跳转指令

条件语句在 CPU 层面映射为条件跳转指令。编译器将 if-else 翻译为如下模式:

比较操作数   → cmp 指令设置标志寄存器
条件跳转     → je/jne/jg/jl 等条件跳转指令
分支代码     → 各分支的机器码块
跳出         → jmp 跳到合并点

分支预测(branch prediction)是 CPU 的重要优化:CPU 猜测跳转方向,提前加载指令流水线。频繁误预测会冲刷流水线,造成显著性能损失。编写对分支预测友好的代码(如将大概率分支放在 if 中)可提升性能。

switch 的跳转表

当 case 值密集连续时,编译器生成跳转表(jump table)——一个函数指针数组,switch 变量作为索引直接跳转,实现 O(1) 分支。若 case 值稀疏,编译器回退为 if-else 链(O(n) 比较)。

这就是 switch 只能接受整型/枚举的原因——需要连续的索引来构建跳转表。

短路求值与安全模式

&&|| 被编译为短路分支结构:

if (ptr != nullptr && *ptr > 0)  // 空指针时 *ptr 不会被求值

编译器不会假设求值顺序,而 && / || 从语言标准层面保证了这一点。


语法

if-else

if (score >= 90) {
    std::cout << "A\n";
} else if (score >= 80) {
    std::cout << "B\n";
} else if (score >= 60) {
    std::cout << "C\n";
} else {
    std::cout << "D\n";
}

else if 链从上到下,首次匹配后跳过后续分支。注意:else if 并非独立关键字,而是 else 后接一个新的 if

switch-case

switch (day) {
    case 1: case 2: case 3: case 4: case 5:
        std::cout << "工作日\n";
        break;
    case 6: case 7:
        std::cout << "周末\n";
        break;
    default:
        std::cout << "无效\n";
        break;
}
要素说明
表达式类型整型、char、enum(不能是浮点、字符串)
case 值编译时常量
break跳出 switch;不写会穿透
&#91;&#91;fallthrough&#93;&#93;C++17 标记有意穿透

C++17 if 初始化语句

// 变量作用域限制在 if-else 内
if (auto it = map.find(key); it != map.end()) {
    std::cout << it->second << '\n';
} else {
    std::cout << "未找到\n";
}

常见陷阱

陷阱错误示例说明
赋值充当条件if (x = 5)= 是赋值,== 才是比较
悬挂 else无花括号时 else 与最近的 if 配对始终用 {} 包裹
空语句体if (x > 0);分号使 if 体为空
浮点等值比较if (a == 0.3)用 epsilon 范围判断

防御性写法:if (5 == x) 误写为 if (5 = x) 会编译错误,能及早发现 bug。


实践

安全模式(利用短路求值):

int arr[] = {1, 2, 3, 4, 5};
if (index >= 0 && index < 5 && arr[index] > 0) {
    // 安全的边界检查+元素访问
}

嵌套条件扁平化:将 if (a) { if (b) { ... } } 重构为 if (a && b) { ... } 减少嵌套层次。

力扣:
力扣: 简单条件判断题 (多条件判断)
力扣: 单条件选择题 (单条件选择)
力扣: 条件逻辑与条件输出题 (条件+输出)

AI 自检提示:询问 AI “if-else 链和 switch 在编译后的机器码层面有何不同,switch 的跳转表在什么条件下生成”。