【问题标题】:How to write perfect error handling in C?如何用 C 编写完美的错误处理?
【发布时间】:2020-06-08 21:31:37
【问题描述】:

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

无论如何,我尝试在一个小型 C89 程序上编写一个完美的错误处理代码,该程序将 in.txt 复制到 out.txt 中。我的目标是编写易于检查和维护的代码。添加新的“资源”或在中间添加可能失败的新函数调用应该很容易。必须尽可能避免代码重复。我的基本设计很简单:所有资源都必须初始化为“空”。如果出现错误,我只需跳转到“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;
}

【问题讨论】:

  • 如果您有工作代码并且正在寻找评论,那么codereview.stackexchange.com 可能是一个更合适的地方。我的观点是,带有 goto 的代码和导致相同代码执行两次的流程并不完美。
  • 更好的方法可能是编写包装函数,这样您就不必重复所有的错误检查。
  • 每当打印有关文件操作错误的错误消息时,该错误消息不包括用于执行操作的路径,小猫就会死亡。 IOW,将“无法打开输入文件”替换为用于打开文件的路径。
  • 没有。 SUCCESSFAILURE 应该是来自 &lt;stdlib.h&gt;EXIT_SUCCESSEXIT_FAILURE。您不需要在免费资源代码中goto handle_error。如果您没有打开输入文件,您可能会认识到您将没有要关闭的输出文件。您应该认识到fread() 可能返回少于缓冲区已满(但多于零)字节并且不处于错误状态 - 特别是如果文件名不是指磁盘文件。您应该在错误消息中报告文件名——这是perror() 的一个特别弱点。
  • How to write perfect error handling 我自己也想知道....

标签: c error-handling


【解决方案1】:

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

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

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

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

【讨论】:

  • a few methods and variables defined in error.h error.h 是 GNU 扩展,它不是 C 语言的一部分。如果您的意思是errno.h,那么errno.h 中只有宏。
猜你喜欢
  • 1970-01-01
  • 2020-04-29
  • 2017-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-18
  • 2021-10-05
  • 2020-05-15
相关资源
最近更新 更多