C if-else 分支
更新时间:2026-08-26。本文是
languages/c/主题入门层第 13 篇。程序开始"有脑子"了——if 让代码能根据条件走不同路径。这一篇除了语法,重点讲两个真坑:=当==、悬空 else。
本文要回答的问题
- C 里"真"和"假"是怎么定义的?
if (x = 5)为什么是 bug?else到底跟哪个if配对?
一、基本语法
c
int score = 85;
if (score >= 90) {
printf("优秀\n");
} else if (score >= 60) {
printf("及格\n");
} else {
printf("不及格\n");
}三个要点:
- 条件写在括号里,
{ }包住要执行的语句; else if可以无限链下去,最终else可省;- 条件可以是任何表达式——非 0 即真,0 即假:
c
if (3) // 真:非 0
if (0) // 假
if (ptr) // 真:指针非 NULL(NULL 就是 0)
if (n % 2) // 真:n 是奇数新手常写 if (ptr != NULL) 和 if (ptr),两者等价,后者更简洁——但初学者按自己顺眼的来,等看多了再简化。
二、经典错误:= 当 ==
c
int x = 5;
if (x = 10) { // 不是"x 等于 10 吗",而是"把 10 赋给 x"!
// 恒真,永远进来
}这是 C 新手第一大坑。x = 10 是赋值,表达式值是 10(非 0),条件永远成立。编译时 -Wall 会警告 suggest parentheses around assignment used as truth value。
防御技巧:把常量写左边——if (10 == x)。这样万一写成 if (10 = x) 编译器直接报错(不能给常量赋值)。这就是传说中的"尤达条件"(Yoda conditions),老 C 程序员爱用。不过现代编译器有 -Wall 兜底,按自己习惯来也行。
三、悬空 else:else 跟谁走?
c
if (a)
if (b)
printf("A和B\n");
else
printf("只有A\n"); // 这个 else 跟哪个 if?else 跟最近的未配对 if 配对——所以上面代码等价于:
c
if (a) {
if (b) {
printf("A和B\n");
} else {
printf("A真B假\n"); // 这才是 else 的实际归属
}
}这跟 Python 的缩进规则完全不一样,是 C 的经典陷阱。解法:永远写花括号,别省。上面第一段代码没有花括号,三个 printf 的归属全靠缩进暗示,极易读错。规范写法:
c
if (a) {
if (b) {
printf("A和B\n");
}
} else {
printf("只有A\n");
}四、三目运算符:条件 ? A : B
c
int max = (a > b) ? a : b; // a>b 时取 a,否则取 b| 写法 | 等价于 |
|---|---|
max = (a > b) ? a : b; | if (a > b) max = a; else max = b; |
三目运算符是表达式(有值),适合"挑一个值"。嵌套三目可读性差,a ? b : c ? d : e 建议拆成 if-else。一行能表达清楚用三目,超过一层就换 if。
五、常见坑对照
| 坑 | 现象 | 对策 |
|---|---|---|
if (x = 5) | 条件恒真 | 用 ==,开 -Wall |
| 省略花括号 | 逻辑归属错乱 | 永远写 {} |
| 悬空 else | else 配错 if | 花括号 + 缩进一致 |
| 三目嵌套 | 读不懂 | 拆成 if-else |
if (n = 0) | 恒假 | 用 == |
六、与本站主线衔接
- 条件分支在汇编里是
cmp+jne/jle等跳转指令,见与汇编、性能剖析衔接; - 分支预测失败是性能热点,见 L4 分支预测;
- 多分支场景用 switch,见下一篇 switch-case。
一句话总结
if 的条件"非 0 即真";= 是赋值、== 才是比较(-Wall 会救你);else 跟最近的未配对 if;花括号永远别省——四条记住,分支结构的基本盘就稳了。