错误处理
errno/perror、返回错误码、assert 断言、setjmp/longjmp
错误处理
C 没有异常机制——错误通过返回值、errno、assert 来传达。处理不好直接崩溃或行为异常。
学完本章你将: 掌握 errno/perror、返回错误码、assert 断言、setjmp/longjmp。
errno —— 全局错误码
c
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main() {
FILE *fp = fopen("不存在.txt", "r");
if (fp == NULL) {
printf("错误码:%d\n", errno);
printf("错误信息:%s\n", strerror(errno));
perror("fopen"); // 打印 "fopen: No such file or directory"
return 1;
}
fclose(fp);
return 0;
}
返回错误码
c
// ✅ 用返回值表示成功/失败
int divide(int a, int b, int *result) {
if (b == 0) return -1; // 错误
*result = a / b;
return 0; // 成功
}
// 调用
int result;
if (divide(10, 0, &result) != 0) {
printf("除数不能为零!\n");
}
assert —— 调试时的安全检查
c
#include <assert.h>
int factorial(int n) {
assert(n >= 0); // 调试时检查条件,发布时可禁用
if (n <= 1) return 1;
return n * factorial(n - 1);
}
💡 assert 只在未定义
NDEBUG时生效。发布版本通常会定义NDEBUG来禁用所有 assert。
setjmp/longjmp —— 类似异常
c
#include <setjmp.h>
jmp_buf buf;
void deepFunction() {
printf("出错,跳回\n");
longjmp(buf, 1); // 跳回 setjmp 处
printf("这行永远不会执行\n");
}
int main() {
if (setjmp(buf) == 0) {
printf("进入深层函数\n");
deepFunction();
} else {
printf("捕获到跳转\n");
}
return 0;
}
⚠️ setjmp/longjmp 是最后的底牌——它跳过正常的栈展开,可能导致资源泄漏。优先用返回值处理错误。