为什么errno,当POSIX函数通过返回-1或NULL指示错误条件时

Vor*_*rac 6 c posix errno

当其中一个UNIX系统函数发生错误时,通常会返回负值,并将整数errno设置为一个值,从而提供其他信息. - UNIX环境中的高级编程,第1.7节

这看起来很奇怪:

  • 它引入了标准库的不同编译单元之间的耦合 - 错误状态未在导致它们的模块中定义.
  • 它引入了实现复杂性,因为errno需要是线程本地的.
  • 它引入了可用性复杂性,因为用户需要检查原始系统调用是否有错误,然后检查errno哪个也是另一个函数调用.

为什么不在返回值中编码错误状态?

Bas*_*tch 8

主要由于历史原因.

请注意,在现实中,errno不是一个普通的全局变量今日(那是在上世纪80年代的情况下).这是今天(C99,C11 ...)宏-通常是扩展到一些函数调用,或许__errno()(和最近的C标准要求 errno做个宏,见n1570第7.5节); 或者它可能会扩展到一些线程局部变量,甚至一些编译器魔法.

errno 想要成为多线程需求的宏,所以我想标准的演变要求它是一些宏

所以你应该#include <errno.h>使用errno宏几乎就像它是一个全局变量,但知道它实际上不是一个.

细节是特定于实现的.查看C标准库的源代码,例如musl-libcerrno/__ errno_location.c中

  int *__errno_location(void)
  {
     return &__pthread_self()->errno_val;
  }
Run Code Online (Sandbox Code Playgroud)

并在include/errno.h公共标题中:

 int *__errno_location(void);
 #define errno (*__errno_location())
Run Code Online (Sandbox Code Playgroud)

和GNU libc有一些非常相似的东西

BTW一些​​系统函数不返回整数(例如mmap),并且一些POSIX函数不指示错误errno,例如dlopen(参见dlerror).因此,在某些标准中很难保证每个错误都可以由返回值指示.

  • [**7.5错误`<errno.h>`**](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf)要求`errno`是一个宏,抑制或隐藏宏是未定义的行为. (2认同)
  • @AndrewHenle:我改进了我的答案,并称赞"作者是谁"...... (2认同)

Fab*_* A. 5

我会为此引用Linus Torvalds

“ errno”是UNIX中少数真正糟糕的愚蠢之一。Linux已修复它,并且不在内部使用它,也永远不会使用它。太糟糕了,用户空间已经修复了正确的错误代码返回内核做,并把它变成向后兼容的“错误号”的愚蠢。

[...]

“ errno”是不应该存在的那些根本破坏的事物之一。在原始UNIX中这是错误的,现在是错误的。

[...]

Linux返回负错误号的方法要好得多。它本质上是线程安全的,并且没有性能下降。当然,这确实取决于是否有足够的结果域,您可以始终将错误返回与良好返回分开,但是实际上对于所有系统调用都是如此。