为什么 errno, when POSIX 函数通过返回 -1 或 NULL 指示错误条件
Why errno, when POSIX function indicate error condition by returning -1 or NULL
When an error occurs in one of the UNIX System functions, a negative value is often returned, and the integer errno
is set to a value, that gives additional information.
-- Advanced Programming in the UNIX Environment, section 1.7
这看起来很奇怪:
- 它引入了标准库的不同编译单元之间的耦合 - 错误状态未在导致它们的模块中定义。
- 它引入了实现的复杂性,因为
errno
需要是本地线程。
- 它引入了可用性复杂性,因为用户需要检查原始系统调用是否有错误,然后检查
errno
这也是另一个函数调用。
为什么不在 return 值中编码错误状态?
主要是由于历史原因。
请注意,实际上 errno
今天 不是 一个普通的全局变量(1980 年代就是这种情况)。今天是 (C99, C11...) 一个宏——通常扩展为一些函数调用,也许 __errno()
(最近的 C 标准 需要 errno
宏,参见 n1570 §7.5);或者它可能会扩展为某个线程局部变量,甚至是一些编译器魔法。
errno
想成为满足 multi-threading 需求的宏,所以我猜标准演变成 require 它是一些宏观
所以你应该 #include <errno.h>
并使用 errno
宏,就好像它是一些全局变量一样,但要知道实际上它不是一个。
详细信息是特定于实现的。查看 C 标准库的源代码,例如musl-libc has in errno/__errno_location.c
int *__errno_location(void)
{
return &__pthread_self()->errno_val;
}
并在 include/errno.h public header:
int *__errno_location(void);
#define errno (*__errno_location())
GNU libc 有一些非常相似的东西
顺便说一句,有些系统函数不会 return 整数(例如 mmap
),有些 POSIX 函数不会通过 errno
指示错误,例如dlopen
(参见 dlerror
)。因此,在某些标准中很难保证每个错误都可以由 returned 值指示。
我会 cite Linus Torvalds 为此。
"errno" is one of those few really bad stupidities in UNIX. Linux has
fixed it, and doesn't use it internally, and never shall. Too bad that
user space has to fix up the correct error code returning that the
kernel does, and turn it into the "errno" stupidity for backwards
compatibility.
[...]
"errno" is one of those fundamentally broken things that should not
exist. It was wrong in original UNIX, it's wrong now.
[...]
The Linux way of returning negative error numbers is much nicer. It's
inherently thread-safe, and it has no performance downsides. Of course, it
does depend on having enough of a result domain that you can always
separate error returns from good returns, but that's true in practice for
all system calls.
When an error occurs in one of the UNIX System functions, a negative value is often returned, and the integer
errno
is set to a value, that gives additional information. -- Advanced Programming in the UNIX Environment, section 1.7
这看起来很奇怪:
- 它引入了标准库的不同编译单元之间的耦合 - 错误状态未在导致它们的模块中定义。
- 它引入了实现的复杂性,因为
errno
需要是本地线程。 - 它引入了可用性复杂性,因为用户需要检查原始系统调用是否有错误,然后检查
errno
这也是另一个函数调用。
为什么不在 return 值中编码错误状态?
主要是由于历史原因。
请注意,实际上 errno
今天 不是 一个普通的全局变量(1980 年代就是这种情况)。今天是 (C99, C11...) 一个宏——通常扩展为一些函数调用,也许 __errno()
(最近的 C 标准 需要 errno
宏,参见 n1570 §7.5);或者它可能会扩展为某个线程局部变量,甚至是一些编译器魔法。
errno
想成为满足 multi-threading 需求的宏,所以我猜标准演变成 require 它是一些宏观
所以你应该 #include <errno.h>
并使用 errno
宏,就好像它是一些全局变量一样,但要知道实际上它不是一个。
详细信息是特定于实现的。查看 C 标准库的源代码,例如musl-libc has in errno/__errno_location.c
int *__errno_location(void)
{
return &__pthread_self()->errno_val;
}
并在 include/errno.h public header:
int *__errno_location(void);
#define errno (*__errno_location())
GNU libc 有一些非常相似的东西
顺便说一句,有些系统函数不会 return 整数(例如 mmap
),有些 POSIX 函数不会通过 errno
指示错误,例如dlopen
(参见 dlerror
)。因此,在某些标准中很难保证每个错误都可以由 returned 值指示。
我会 cite Linus Torvalds 为此。
"errno" is one of those few really bad stupidities in UNIX. Linux has fixed it, and doesn't use it internally, and never shall. Too bad that user space has to fix up the correct error code returning that the kernel does, and turn it into the "errno" stupidity for backwards compatibility.
[...]
"errno" is one of those fundamentally broken things that should not exist. It was wrong in original UNIX, it's wrong now.
[...]
The Linux way of returning negative error numbers is much nicer. It's inherently thread-safe, and it has no performance downsides. Of course, it does depend on having enough of a result domain that you can always separate error returns from good returns, but that's true in practice for all system calls.