A.1 Unix 系统中的错误处理

A.1 Unix 系统中的错误处理

本书中我们遇到的系统级函数调用使用三种不同风格的返回错误:Unix 风格的、Posix 风格的和 GAI 风格的。

1. Unix 风格的错误处理

forkwait 这样 Unix 早期开发出来的函数(以及一些较老的 Posix 函数)的函数返回值既包括错误代码,也包括有用的结果。例如,当 Unix 风格的 wait 函数遇到一个错误(例如没有子进程要回收),它就返回 -1,并将全局变量 errno 设置为指明错误原因的错误代码。如果 wait 成功完成,那么它就返回有用的结果,也就是回收的子进程的 PID。Unix 风格的错误处理代码通常具有以下形式:

if ((pid = wait(NULL)) < 0) {
    fprintf(stderr, "wait error: %s\n", strerror(errno));
    exit(0);
}

strerror 函数返回某个 errno 值的文本描述。

2. Posix 风格的错误处理

许多较新的 Posix 函数,例如 Pthread 函数,只用返回值来表明成功(0)或者失败(非 0)。任何有用的结果都返回在通过引用传递进来的函数参数中。我们称这种方法为 Posix 风格的错误处理。例如,Posix 风格的 pthread_create 函数用它的返回值来表明成功或者失败,而通过引用将新创建的线程的 ID(有用的结果)返回放在它的第一个参数中。Posix 风格的错误处理代码通常具有以下形式:

if ((retcode = pthread_create(&tid, NULL, thread, NULL)) != 0) {
    fprintf(stderr, "pthread_create error: %s\n", strerror(retcode));
    exit(0);
}

strerror 函数返回 retcode 某个值对应的文本描述。

3. GAI 风格的错误处理

getaddrinfo(GAI)和 getnameinfo 函数成功时返回零,失败时返回非零值。GAI 错误处理代码通常具有以下形式:

if ((retcode = getaddrinfo(host, service, &hints, &result)) != 0) {
    fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(retcode));
    exit(0);
}

gai_strerror 函数返回 retcode 某个值对应的文本描述。

4. 错误报告函数小结

贯穿本书,我们使用下列错误报告函数来包容不同的错误处理风格:

#include "csapp.h"

void unix_error(char *msg);
void posix_error(int code, char *msg);
void gai_error(int code, char *msg);
void app_error(char *msg);

返回:无。

正如它们的名字表明的那样,unix_errorposix_errorgai_error 函数报告 Unix 风格的错误、Posix 风格的错误和 GAI 风格的错误,然后终止。包括 app_error 函数是为了方便报告应用错误。它只是简单地打印它的输入,然后终止。图 A-1 展示了这些错误报告函数的代码。

code/src/csapp.c

void unix_error(char *msg) /* Unix-style error */
{
    fprintf(stderr, "%s: %s\n", msg, strerror(errno));
    exit(0);
}

void posix_error(int code, char *msg) /* Posix-style error */
{
    fprintf(stderr, "%s: %s\n", msg, strerror(code));
    exit(0);
}

void gai_error(int code, char *msg) /* Getaddrinfo-style error */
{
    fprintf(stderr, "%s: %s\n", msg, gai_strerror(code));
    exit(0);
}

void app_error(char *msg) /* Application error */
{
    fprintf(stderr, "%s\n", msg);
    exit(0);
}

图 A-1 错误报告函数