Zed Shaw 的“以艰难的方式学习 C”尽管存在所有缺陷,但其中有一个关于“C 错误处理问题”的精彩部分,您可能会觉得有趣。
我认为解决此问题的一种方法是使用调试宏来包装 C 提供的全局“errno”值。
下面的 'dbg.h' 代码取自 Zed Shaw 的书:
dbg.h:
#ifndef __dbg_h__
#define __dbg_h__
#include <stdio.h>
#include <errno.h>
#include <string.h>
#ifdef NDEBUG
#define debug(M, ...)
#else
#define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n",\
__FILE__, __LINE__, ##__VA_ARGS__)
#endif
#define clean_errno() (errno == 0 ? "None" : strerror(errno))
#define log_err(M, ...) fprintf(stderr,\
"[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__,\
clean_errno(), ##__VA_ARGS__)
#define log_warn(M, ...) fprintf(stderr,\
"[WARN] (%s:%d: errno: %s) " M "\n",\
__FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)
#define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n",\
__FILE__, __LINE__, ##__VA_ARGS__)
#define check(A, M, ...) if(!(A)) {\
log_err(M, ##__VA_ARGS__); errno=0; goto error; }
#define sentinel(M, ...) { log_err(M, ##__VA_ARGS__);\
errno=0; goto error; }
#define check_mem(A) check((A), "Out of memory.")
#define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__);\
errno=0; goto error; }
#endif
在您想要检查的代码中,您可以执行以下操作:
#include <stdio.h>
#include "dbg.h"
int div(int x, int y) {
check ( y != 0, "Division by zero!");
return x / y;
error:
log_err("Div by zero error.");
return 0;
}
int main() {
printf("%d", div(4, 2));
printf("%d", div(4, 0));
}
这样,您的错误就会被“dbg.h”中的代码捕获和处理。
现在这有一个明显的问题,即当调用 div(x, 0) 时:div 返回 0。问题是 div() 必须返回一个 int,并且所有 int 都可以由 div(x, y) 的某种有效组合产生对于整数 x 和 y。
一种解决方案是将 div 包装在另一个函数中:
#include <stdio.h>
#include <stdlib.h>
#include "dbg.h"
char *div_interface(int x, int y) {
check ( y != 0, "Division by zero!");
char *buffer = malloc(100);
sprintf(buffer, "%d", (x / y));
return buffer;
error:
log_err("Div by zero error.");
char *err_ret= strdup("Div by zero error.");
return err_ret;
}
int main() {
char *div_1 = div_interface(4, 2);
printf("%s\n", div_1);
free(div_1);
char *div_2 = div_interface(4, 0);
printf("%s\n", div_2);
free(div_2);
}
虽然这也不是特别优雅!然后调用者必须进行从 char* 到 int 的转换...