#include <errno.h> // errno
#include <stdarg.h> // 标准C头文件,可变参数
#include "ourhdir.h" // 自定义的头文件
// static:表示该函数只能在该文件中使用
// va_list的指针类型其实是char *
// 函数声明中使用static,函数实现的函数头中要表里如一
static void err_doit(int, const char *, va_list);
// va_list类型的变量通常起名为:ap, 数组指针?
static void err_doit(int errnoflag, const char *fmt, va_list ap) {
int errno_save;
char buf[MAXLINE];
memset(buf, 0, MAXLINE); // 对自动变量初期化
// 在使用errno的时候首先将其保存在自动变量中
// 防止在使用的过程中值发生变化
errno_save = errno;
// 将可变参数格式化到buf中
vsprintf(buf, fmt, ap);
// 根据传入的标识决定是否将errno信息放在buf里打印出来
if (errnoflag) {
// 利用strerror函数将errno转化为可读字符串
sprintf(buf+strlen(buf), ": %s", strerror(errno_save));
}
strcat(buf, "\n"); // 在字符串尾端添加换行符
// L24可改写,省去L27
// sprintf(buf + strlen(buf, ": %s\n", strerror(errno_save)));
// 刷新标准输出缓冲区
// 该文件中出现的出错处理函数都是都是直接输出到标准出错,为了防止标准出错和标准输出是同一个,即将标准错误重定位到标准输出,在此刷新标准出错。
// 如果标准输入输出涉及到终端设备,则他们是行缓冲的,否则是全缓冲的
// 标准错误是无缓冲的
fflush(stdout);
fputs(buf, stderr); // 将buf输出到标准出错
fflush(NULL); // 刷新所有的标准流,前面已经做了关于缓冲的操作,为什么这里要刷新所有的标准流?保留L40,删去L36是否完全合理?
return;
}
// const表示该参数只读
// 从const切开,const是类型修饰符,类型是char,即*fmt的类型是char。
// *fmt的值不能修改。
// 函数中的可变参数用...表示,宏中的可变参数用args...表示。
// 从代码实现的角度来看...如何实现的?
// 输出所有信息,return退出
void err_ret(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
err_doit(1, fmt, ap);
va_end(ap);
return;
}
// 输出所有的信息,exit退出
void err_sys(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
err_doit(1, fmt, ap);
va_end(ap);
exit(1); // 为什么exit(1)而不是exit(0)?
}
// 输出所有错误的信息,产生core文件
void err_dump(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
err_doit(1, fmt, ap);
va_end(ap);
abort(); // 向自己进程发送SIGABORT信号,产生core文件,然后程序终止
exit(1); // 该语句不会被执行,为什么知道有些语句不会被执行,还要写?
}
// 仅仅为了输出想要输出的信息,即printf的功能
void err_msg(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
err_doit(0, fmt, ap);
va_end(ap);
return;
}
// 输出信息,然后exit退出
void err_quit(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
err_doit(0, fmt, ap);
va_end(ap);
exit(1);
}
APUE-错误处理函数
最新推荐文章于 2023-03-13 23:46:04 发布
