首页 > 解决方案 > 如何用 C 编写完美的错误处理?

问题描述

众所周知,编写“完美”的错误处理代码在 C 中很难(而在其他语言中则非常困难)。开发人员几乎总是忘记或丢弃的是在清理资源时处理错误。例如,忽略 fclose 返回值是危险的。

无论如何,我尝试在一个将 in.txt 复制到 out.txt 的小型 C89 程序上编写完美的错误处理代码。我的目标是编写易于检查和维护的代码。添加新的“资源”或在中间添加可能失败的新函数调用应该很容易。必须尽可能避免代码重复。我的基本设计很简单:所有资源都必须初始化为“空”。如果出现错误,我只需跳转到“handle_error”。最后我总是叫“free_resources”。“handle_error”和“free_resources”部分可以执行多次(例如,如果在释放资源时发生错误)而不会出现问题。

我的代码“完美”吗?

#include <stdio.h>

typedef int status;

#define SUCCESS 1
#define FAILURE 0

#define INPUT_FILE "in.txt"
#define OUTPUT_FILE "out.txt"

#define BUFFER_SIZE 2097152

char buffer[BUFFER_SIZE];

status copy_file()
{
        FILE *input_file = NULL;
        FILE *output_file = NULL;
        size_t read_bytes;
        size_t written_bytes;
        status result;

        input_file = fopen(INPUT_FILE, "rb");
        if (!input_file) {
                perror("Failed to open input file");
                goto handle_error;
        }

        output_file = fopen(OUTPUT_FILE, "wb");
        if (!output_file) {
                perror("Failed to open output file");
                goto handle_error;
        }

        while (1) {
                read_bytes = fread(buffer, 1, sizeof(buffer), input_file);
                if (read_bytes != sizeof(buffer) && ferror(input_file)) {
                        fprintf(stderr, "Failed to read from input file.\n");
                        goto handle_error;
                }
                written_bytes = fwrite(buffer, 1, read_bytes, output_file);
                if (written_bytes != read_bytes) {
                        fprintf(stderr, "Failed to write to output file.\n");
                        goto handle_error;
                }
                if (read_bytes != sizeof(buffer))
                        break;
        }

        result = SUCCESS;

free_resources:
        if (output_file) {
                if (fclose(output_file)) {
                        output_file = NULL;
                        perror("Failed to close output file");
                        goto handle_error;
                }
                output_file = NULL;
        }

        if (input_file) {
                if (fclose(input_file)) {
                        input_file = NULL;
                        perror("Failed to close input file");
                        goto handle_error;
                }
                input_file = NULL;
        }

        return result;
handle_error:
        result = FAILURE;
        goto free_resources;
}

int main()
{
        return copy_file() ? 0 : 1;
}

标签: cerror-handling

解决方案


C 语言不提供任何对错误处理的直接支持。但是,error.h 头文件中定义的一些方法和变量可用于在函数中使用 return 语句来指出错误。在 C 语言中,函数在发生任何错误时返回 -1 或 NULL 值,并且使用错误代码设置全局变量 errno。因此返回值可用于在编程时检查错误。

每当用 C 语言进行函数调用时,都会关联一个名为 errno 的变量。它是一个全局变量,可用于根据其值识别函数执行时遇到的错误类型。

C 语言使用以下函数来表示与 errno 相关的错误消息:

  • perror():返回传递给它的字符串以及当前 errno 值的文本表示。
  • strerror() 在 string.h 库中定义。此方法返回一个指向当前 errno 值的字符串表示形式的指针。

推荐阅读