C 语言的错误处理(Error Handling)机制
                           
天天向上
发布: 2025-04-05 23:59:30

原创
185 人浏览过

本文将从实战、标准规范、语言机制和库支持等角度,全面系统地讲解 C 语言的错误处理(Error Handling)机制


📘 一、C 语言错误处理概述

C 语言不像 Java、Python 有内建的异常机制(如 try-catch),但它提供了多种错误处理手段,包括:

方式简介
返回码机制函数通过返回值传达成功/失败
errno 全局变量由标准库函数设置,表示错误类型
perror()strerror()打印或解释错误
自定义错误处理函数用户根据返回码做判断
setjmp()longjmp()实现异常跳转(复杂、慎用)
信号(signal)机制处理运行时错误(如除零、段错误)

📂 二、返回码机制(Return Code)

✅ 通用函数返回值判断

int result = some_function();
if (result != 0) {
    // 错误处理逻辑
}

例:fopen 打开文件失败时返回 NULL

FILE *fp = fopen("data.txt", "r");
if (fp == NULL) {
    perror("Failed to open file");
}

📌 三、errno 错误码机制

errno<errno.h> 中定义的全局变量,由许多标准库函数在出错时设置。

常见 errno 值(来自 POSIX 标准)

宏常量错误码含义
EPERM1操作不被允许
ENOENT2文件或目录不存在
EIO5I/O 错误
ENOMEM12内存不足
EACCES13权限被拒绝
EINVAL22参数无效

示例:

#include <stdio.h>
#include <errno.h>
#include <string.h>

int main() {
    FILE *fp = fopen("no_such_file.txt", "r");
    if (!fp) {
        printf("errno: %d\n", errno);
        printf("Error: %s\n", strerror(errno)); // 或用 perror()
    }
    return 0;
}

🔍 四、perror() 与 strerror()

perror(const char *msg)

输出形式为:msg: 错误信息

perror("fopen failed");

strerror(int errnum)

返回错误码对应的字符串

printf("Error: %s\n", strerror(errno));

⚠️ 五、setjmp() 和 longjmp() —— C 中的“异常跳转”

来自 <setjmp.h>,可以用来模拟“异常处理结构”,但结构复杂、跳转混乱,慎用

#include <stdio.h>
#include <setjmp.h>

jmp_buf buf;

void my_function() {
    printf("Throwing error!\n");
    longjmp(buf, 1);
}

int main() {
    if (setjmp(buf)) {
        printf("Error caught via longjmp\n");
    } else {
        my_function();
    }
    return 0;
}

🔁 类似 trythrow,但不推荐用于日常代码,尤其是在复杂项目中。


🚦 六、信号机制(signal)处理运行时错误

来自 <signal.h>,例如处理除零、段错误、终止信号等。

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>

void handler(int sig) {
    printf("Caught signal: %d\n", sig);
    exit(1);
}

int main() {
    signal(SIGFPE, handler); // 捕获除零错误

    int x = 1 / 0; // 除零,触发 SIGFPE
    return 0;
}

🧠 七、专业建议:如何设计你的错误处理逻辑?

  1. 封装函数返回状态码(建议使用 enum)
  2. 封装错误日志记录(如 log_error 函数)
  3. 避免使用 setjmp/longjmp,维护困难
  4. 合理使用 errno,但不要依赖其“准确性”
  5. 对所有资源访问(内存、文件、网络)进行判空检查
  6. 必要时统一错误处理机制,提升可维护性

🧪 八、实战示例:文件读取 + 错误检查

#include <stdio.h>
#include <errno.h>
#include <string.h>

int read_file(const char *filename) {
    FILE *fp = fopen(filename, "r");
    if (!fp) {
        fprintf(stderr, "Error opening file '%s': %s\n", filename, strerror(errno));
        return errno;
    }

    // ... 文件操作 ...

    fclose(fp);
    return 0;
}

📚 九、权威资料 & 出站链接

类型链接/来源
C 标准头文件 <errno.h>https://en.cppreference.com/w/c/error/errno
错误码列表 errnohttps://man7.org/linux/man-pages/man3/errno.3.html
C 标准库手册https://en.cppreference.com/w/c
setjmp/longjmphttps://en.cppreference.com/w/c/program/setjmp
signal() 函数文档https://man7.org/linux/man-pages/man2/signal.2.html

✅ 十、总结表

错误处理方式适用场景是否推荐
返回值检查✅ 所有函数调用✅ 强烈推荐
errno + perror/strerror✅ 库函数出错✅ 推荐
setjmp/longjmp🚫 非结构化跳转❌ 不推荐
signal✅ 系统级错误,如 SIGSEGV⚠️ 有限度使用

发表回复 0

Your email address will not be published. Required fields are marked *