C 没有 C++/Java 那套 try-catch 异常机制,错误处理全靠"函数的返回值 + 全局 errno"。这套路看着原始,但学会之后,任何 C 项目的错误排查都有章法可循。
errno:出错时的那串错误码
errno 是 errno.h 里定义的全局变量。标准库函数一失败,就把对应的错误码存进去。最常用的几个:
| errno | 含义 |
|---|---|
1 | Operation not permitted(操作不允许) |
2 | No such file or directory(文件不存在) |
5 | I/O error |
12 | Out of memory(内存不足) |
13 | Permission denied(权限不足) |
最基本的用法,打开不存在的文件:
#include <stdio.h>
#include <errno.h>
int main() {
FILE *fp = fopen("missing.txt", "r");
if (fp == NULL) {
printf("Error Code: %d\n", errno);
perror("Error");
}
return 0;
}输出:
Error Code: 2
Error: No such file or directory几种常用的错误处理手段
1. if-else 判断返回值
最基础也最常见。函数返回 NULL / -1 就是出错信号:
FILE* fp;
fp = fopen("test.txt", "r");
if (fp == NULL) {
printf("File opening error\n");
} else {
printf("File open successfully\n");
}2. perror():打印错误描述
perror() 把你自己写的消息和 errno 对应的描述拼一起输出到标准错误流:
#include <errno.h>
#include <stdio.h>
int main() {
FILE* fp = fopen("test.txt", "r");
printf("Value of errno: %d\n", errno);
perror("Message from perror");
return 0;
}输出:
Value of errno: 2
Message from perror: No such file or directory3. strerror():拿到错误描述字符串
strerror() 把 errno 转成可读的文本,方便自己格式化输出:
#include <errno.h>
#include <stdio.h>
#include <string.h>
int main() {
FILE* fp = fopen("test.txt", "r");
printf("Value of errno: %d\n", errno);
printf("The error message is : %s\n", strerror(errno));
return 0;
}输出:
Value of errno: 2
The error message is : No such file or directory4. ferror():检查文件操作是否出错
写文件后查一下有没有出错:
#include <stdio.h>
int main() {
FILE *fptr = fopen("test.txt", "w");
if (fptr == NULL) return 1;
fprintf(fptr, "Hello, online-compiler!");
if (ferror(fptr) == 0)
printf("Data written successfully.\n");
fclose(fptr);
return 0;
}5. feof():判断是否读到文件尾
读文件时判断到没到结尾,避免越读越出错:
#include <stdio.h>
int main() {
FILE *fp = fopen("test.txt", "r");
if (fp == NULL)
return 0;
do {
char c = fgetc(fp);
if (feof(fp))
break;
printf("%c", c);
} while (1);
fclose(fp);
return 0;
}6. clearerr():清掉 EOF / 错误标记
文件读到 EOF 后,feof 标记会一直挂着。clearerr() 能清掉,让流可以继续用:
#include <stdio.h>
int main() {
FILE *fptr = fopen("test.txt", "w+");
fprintf(fptr, "Hello, online-compiler!");
while (fgetc(fptr) != EOF);
if (feof(fptr)) {
printf("EOF encounter\n");
}
clearerr(fptr);
if (!feof(fptr)) {
printf("Reset the EOF successfully\n");
}
fclose(fptr);
return 0;
}输出:
EOF encounter
Reset the EOF successfully退出状态:exit() 告诉系统成没成
exit() 能把程序状态码传给操作系统。标准定义了两个常量:EXIT_SUCCESS 和 EXIT_FAILURE。
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
FILE* fp = fopen("test.txt", "rb");
if (fp == NULL) {
printf("Value of errno: %d\n", errno);
printf("Error opening the file: %s\n", strerror(errno));
perror("Error printed by perror");
exit(EXIT_FAILURE); /* 失败退出 */
printf("I will not be printed\n"); /* 根本不会执行 */
} else {
fclose(fp);
exit(EXIT_SUCCESS); /* 成功退出 */
}
return 0;
}注意 exit() 一调用,后面代码直接不跑了,别在 exit 后面写依赖执行的逻辑。
不靠函数也能防的错
很多错误压根不用走到标准库,写代码时就提前拦下:
#include <stdio.h>
int main() {
int num1 = 10, num2 = 0;
if (num2 == 0)
printf("Error: Division by zero is not allowed\n");
else
printf("Result: %d", num1 / num2);
return 0;
}输出:
Error: Division by zero is not allowed除零、越界、非法输入这类,用 if 提前判断,程序根本不会走到崩溃那一步。
套路总结
C 语言的错误处理可以归成三句话:函数返回值告诉你成没成,errno 告诉你为什么,if/perror/strerror 把这两件事讲给人听。写健壮代码,就是每一步都检查、每一条错误路径都交代清楚。