在程序执行过程中,当判断到某个函数执行失败时,通常会调用return退出程序。在Linux系统下对常见的错误做了一个编号,每一个编号都代表着每一种不同的错误类型,当函数执行发生错误的时候,操作系统会将这个错误所对应的编号赋值给errno变量,每一个进程(程序)都维护了自己的errno变量,它是程序中的全局变量,该变量用于存储就近发生的函数执行错误编号,也就意味着下一次的错误码会覆盖上一次的错误码。
所以由此可知道,当程序中调用函数发生错误的时候,操作系统内部会通过设置程序的 errno变量来告知调用者究竟发生了什么错误。
errno本质上是一个int类型的变量,用于存储错误编号,但是需要注意的是,并不是执行所有的系统调用或C库函数出错时,操作系统都会设置errno。通过man手册可以查到,譬如以open函数为例,执行"man 2 open"打开open函数的帮助信息,找到函数返回值描述段,如下所示,当函数返回错误时会设置errno:
RETURN VALUE
open(), openat(), and creat() return the new file descriptor (a nonnegative integer), or -1 if an error occurred (in which case, errno is set appropriately). 示例:
#include
#include
int main()
{
printf("errno1=%dn", errno);
fopen("errno", "r");
printf("errno2=%dn", errno);
return 0;
}
编译运行并查看测试结果
errno1=0
errno2=2
此处errno2=2,由于open函数打开了一个不存在的文件,errno的错误码则为ENOENT(文件不存在),对应的int数值就是2。关于errno的更多错误宏的定义,可以阅读/usr/include/asm-generic/errno-base.h
/usr/include/asm-generic/errno.h
$ cat /usr/include/asm-generic/errno-base.h
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _ASM_GENERIC_ERRNO_BASE_H
#define _ASM_GENERIC_ERRNO_BASE_H
#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Argument list too long */
......
由于errno仅返回数值,还需查阅错误宏定义才能知道具体错误原因,由此引入以下两个标准c库函数。
perror
用于在发生系统调用错误时输出有关错误信息的描述。当一个系统调用或库函数发生错误时,通常会将全局变量errno设置为一个特定的错误码。perror函数读取errno的值,并根据这个值生成相应的错误描述。然后,将错误描述与传入的字符串参数拼接,并输出到标准错误流。
1.头文件
#include
2.函数原型
void perror(const char *str);
3.参数
str:表示一个指向常量字符的指针,用于提供上下文信息。在输出错误消息时,这个字符串将作为错误消息的前缀(可以主动的去描述这个错误信息的内容)。
4.返回值
无。
5.示例
#include
int main()
{
FILE *fp = fopen("perror", "r"); //打开一个不存在的文件perror
if (!fp) {
perror("perror test");
return -1;
}
fclose(fp);
return 0;
}
6.编译运行并查看测试结果
perror test: No such file or directory //报错提示没有这个文件
strerror
用于生成描述错误代码的字符串。
1.头文件
#include
2.函数原型
char *strerror(int errnum);
3.参数
errnum:错误标号,通常用errno。
4.返回值
会返回一个指向描述该错误的字符串的指针。
5.示例
#include
#include
#include
int main()
{
FILE *fp = fopen("strerror", "r");
if (!fp) {
fprintf(stdout, "strerror test: %sn", strerror(errno));
return -1;
}
fclose(fp);
return 0;
}
6.编译运行并查看测试结果
strerror test: No such file or directory