1. 常见的几种出错处理方式

如果返回值是 int 类型,并且返回的数据是非负数,一般使用 -1 代表出错,然后非负数代表正确的返回值。

如果返回值是 int 类型,但返回的数据有可能是负数,用指针接收返回数据,也就是将其中一个参数作为输出返回,用返回值 0 代表成功,返回 -1 代表出错。

如果返回值是指针,一般用 NULL 代表出错,非空代表正确。

如果不需要考虑错误处理,返回值用 void 即可。简单总结这几种情况,以上几种情况属于一般情况,当然也可能会有特列。

2. 设计函数的错误处理

  • 打印传入的字符串
    对应上述第 4 种情况,不需要返回值,一般不会出错,不需要考虑错误处理。

    void print(const char *string) {
     printf("%s\n", string);
    }

  • 判断传入的字符串是否正确
    判断传入的字符串是否是 error,如果是返回 ok,不是的话报错。对应上述第 3 种情况,如果不是返回 NULL。

    char *is_error(const char *str){
     if (!strcmp(str, "error"))
         return "ok";
     else
         return NULL;
    }
  • 返回 1-10 随机数
    返回 1-10 随机数,如果随机数是 5,返回 -1 代表出错,若不是则返回 1-10 的随机数。

    int rand10() {
     srand(time(0));
     int num = rand() % 10 + 1;
     if (num == 5)
         return -1;
     else
         return num
    }
  • 比较两个整数的大小
    比较两个整数的大小,返回最大值,如果相等则报错。对应上述第 2 种情况,返回值可能是负数,不能直接返回 -1 来表示错误,需要增加指针参数来接收最大值的返回。

    int max(int a, int b, int *ret) {
     if (a == b)
         return -1;
     *ret = (a > b) ? a : b;
     return 0;
    }

当然文中举例都非常简单,主要是想说明 C 语言程序中我们要关注错误的处理,这样有助于对程序的错误的快速排查。当然错误的时候不止可以返回 -1,如果系统比较复杂,可以设置多种错误码来区分程序中的各类错误,最好每个错误码都对应具体的错误原因。

3. 错误处理函数

C语言中,系统预先设定了一些错误,每种错误都由错误编号和错误信息组成。每个错误编号对应一种错误信息。

errno 外部全局变量,提供了错误编号,需要先出错,再用errno,函数出错会改变 errno 的值,但成功不会改值,也不会清零。所以它不能用于判断是否出错,errno 直接拿来使用即可,不过程序中需要加头文件 error.h。

strerror 函数通过错误编号得到错误信息,完成从错误编号到错误信息的转换,与 errno 没有直接的关系,是否产生错误都可以使用它。

printf("%s\n", strerror(errno);

perror 函数打印错误信息并自动换行,这个函数经常使用,参数是附加的信息,能更好的帮助程序员定位错误。

perror("open file error: ");
// 前提是打开文件出错

perror 函数是找 errno,打印 errno 对应的错误信息,先发生错误而后才能使用。errno 针对大多数函数有效,但也有一些函数不能使用 errno 作为错误记录,比如线程函数,因为线程出错会将之前的错误覆盖,导致不能够准确判断出具体错误。