为什么 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

这看起来很奇怪:

为什么不在 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.