c - 如何用 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;
}
解决方案
C 语言不提供任何对错误处理的直接支持。但是,error.h 头文件中定义的一些方法和变量可用于在函数中使用 return 语句来指出错误。在 C 语言中,函数在发生任何错误时返回 -1 或 NULL 值,并且使用错误代码设置全局变量 errno。因此返回值可用于在编程时检查错误。
每当用 C 语言进行函数调用时,都会关联一个名为 errno 的变量。它是一个全局变量,可用于根据其值识别函数执行时遇到的错误类型。
C 语言使用以下函数来表示与 errno 相关的错误消息:
- perror():返回传递给它的字符串以及当前 errno 值的文本表示。
- strerror() 在 string.h 库中定义。此方法返回一个指向当前 errno 值的字符串表示形式的指针。
推荐阅读
- android - 隐藏/显示片段中的导航元素
- javascript - 如何识别移动设备中的地址栏?
- c - 在汇编中使用 fgets 时出现分段错误错误?
- python - COCO python API已安装但无法导入
- python - TensorFlow 模型的成本始终为 0
- stm32 - STM32F303 发现 - USART_IT_RXNE 从不接收 antyhing(无 DMA/无 HAL)
- javascript - 解析 img src 和 background-image url 时使用字符串路径而不是要求
- docker - 为什么我无法获取 ocaml/opam:ubuntu-16.04_ocaml-4.03.0 docker Image?
- c++ - 转换为大写会在末尾添加一个额外的字母?
- c++ - 如何 typedef 绑定一个成员方法,然后将该类型用作模板参数?