表达式语句
表达式语句是最常见、也最容易被忽略的一类语句:它的形式是“表达式后接分号”。程序会先对表达式求值,再丢弃表达式结果(除非表达式本身有副作用)。
1. 基本形式
count++; /* 修改对象状态 */
sum += value; /* 复合赋值 */
printf("ok\n"); /* 函数调用 */2
3
可能的输出(示例):
<输出与输入或平台相关,请以实际运行为准>
这三行都是表达式语句。它们的价值不在“产生一个值”,而在“完成一次动作”:更新对象、写输出、触发函数副作用。
2. 空表达式语句
只有一个分号 ; 也是合法语句,称为空语句。它常见于循环体故意留空的场景。
while (*p++ != '\0') {
;
}2
3
运行结果:该代码块主要用于语法或结构说明,单独运行通常无终端输出。
空语句并不“什么都不做”;它表示“循环控制逻辑全部写在条件里”。如果代码意图不够清楚,建议加注释或改成显式块。
3. 常见误用
把条件判断后面误写一个分号,会导致控制语句失效。
if (ready) {
do_work();
}2
3
运行结果:该代码块主要用于语法或结构说明,单独运行通常无终端输出。
相比
if (ready);
{
do_work();
}2
3
4
运行结果:该代码块主要用于语法或结构说明,单独运行通常无终端输出。
第二段中 if 实际控制的是空语句,后面的块会无条件执行。这类问题在代码评审中很常见,务必通过格式化和告警规则提前拦截。
4. 有意忽略返回值时的写法
有些函数返回值在当前语境下确实可以忽略。此时可以显式写 (void) 转换,表达“这里是有意丢弃”,同时避免和遗漏检查混在一起。
#include <stdio.h>
int main(void) {
(void)puts("hello");
return 0;
}2
3
4
5
6
可能的输出(示例):
<输出与输入或平台相关,请以实际运行为准>
这仍然是表达式语句,但意图更清楚:这次调用只关心副作用,不关心返回值。
5. 赋值语句与条件语句的界线
赋值表达式本身可以构成表达式语句,但在条件语句中混入赋值会增加误读风险。若代码意图是“更新状态”,通常写成独立表达式语句更清楚;若确实要在条件里赋值,应配合括号与注释明确意图。
6. 完整表达式边界
每条表达式语句都是一个完整表达式边界。前一条表达式语句中的副作用会在下一条开始前完成。把复杂逻辑拆成多条表达式语句,不仅更易读,也更容易稳定控制求值时序。
7. 与 for 三段式的区分
for (init; cond; step) 中的 init、cond、step 都是表达式位置,但它们不等同于普通“表达式语句 + 分号”。尤其 step 部分常写成逗号表达式或复合更新,阅读时应把它视为循环控制的一部分,而不是独立动作语句。若 step 逻辑过重,拆回循环体往往更清楚。
8. 把副作用控制在可命名步骤里
表达式语句最适合承载单一副作用,比如一次赋值、一次函数调用、一次状态推进。当一个表达式同时承担“更新状态、判定条件、触发 I/O”多重目的时,通常应拆分为多条语句并引入中间命名结果。这样做能让调试断点、日志定位和错误回退路径都更直接。