错误处理
C 语言没有内建的异常机制 (Exception)。在实践中,错误处理通常依赖以下三类工具:
- 断言:用
assert在调试阶段暴露“本不该发生”的逻辑错误。 - 错误码:通过函数返回值表达失败,再用
errno(或自定义错误码)补充失败原因。 - 信号:处理异步中断(如
SIGINT),或理解进程因严重错误而终止的路径(如SIGSEGV)。
本章只讨论 C 标准库提供的三组能力:<assert.h>、<errno.h>、<signal.h>。
1. 何时使用哪一种
| 场景 | 推荐手段 | 目的 |
|---|---|---|
| 代码内部的不变量被破坏(逻辑 bug) | assert | 尽快在开发阶段失败并定位问题。 |
| 外部输入/环境导致的失败(用户输入、文件不存在、资源不足等) | 返回值 + errno(或自定义错误码) | 让调用者有机会处理或上报错误。 |
| 异步事件(如 Ctrl+C)或运行时致命错误 | signal | 做最小化的收尾(或记录)后退出;不把它当作“正常控制流”。 |
重要
不要把 assert 当作“运行时的错误处理”。定义了 NDEBUG 后,assert 可能会被完全移除,表达式也不会被求值。
2. 本章目录
3. 习题
- 分别给出一个例子,说明“应该用
assert”与“应该用返回值 +errno”的区别;并解释原因。 - 设计一个函数
int parse_u32(const char* s, uint32_t* out);:- 当
s == NULL或out == NULL时,选择assert还是返回错误?说明理由。 - 当字符串不是合法数字或超出范围时,返回什么错误信息(错误码/
errno)?说明理由。
- 当
- 写一个小程序:循环读取一行输入并处理;当收到
SIGINT(Ctrl+C)时退出。要求:信号处理函数里只设置一个标志位,不做 I/O。