简体   繁体   English

为什么errno,当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. 当其中一个UNIX系统函数发生错误时,通常会返回负值,并将整数errno设置为一个值,从而提供其他信息。 -- Advanced Programming in the UNIX Environment, section 1.7 - UNIX环境中的高级编程,第1.7节

This seems weird: 这看起来很奇怪:

  • It introduces coupling between different compilation units of the standard library - error states are not defined in the modules causing them. 它引入了标准库的不同编译单元之间的耦合 - 错误状态未在导致它们的模块中定义。
  • It introduces implementation complexity, because errno needs to be thread local. 它引入了实现复杂性,因为errno需要是线程本地的。
  • It introduces usability complexity because the user needs to check that the original system call is in error, and then check errno Which is also another function call. 它引入了可用性复杂性,因为用户需要检查原始系统调用是否有错误,然后检查errno哪个也是另一个函数调用。

Why not encode the error states in the return values? 为什么不在返回值中编码错误状态?

For historical reasons mostly. 主要由于历史原因。

Notice that in reality, errno is not an ordinary global variable today (that was the case in the 1980s). 请注意,实际上, errno今天不是普通的全局变量(在20世纪80年代就是这种情况)。 It is today (C99, C11...) a macro - usually expanded to some function call, perhaps __errno() (and recent C standard requires errno to be a macro, see n1570 §7.5); 这是今天(C99,C11 ...)宏-通常是扩展到一些函数调用,或许__errno()和最近的C标准要求 errno是一个宏,见n1570第7.5节); or it might be expanded to some thread local variable, or even some compiler magic. 或者它可能会扩展到一些线程局部变量,甚至一些编译器魔法。

errno wants to be a macro for multi-threading needs, so I guess that standards evolved to require it to be some macro errno希望成为多线程需求的宏,所以我猜这些标准发展到要求它成为一些宏

So you should #include <errno.h> and use the errno macro nearly as if it was some global variable, but knowing that in fact it is not one. 所以你应该#include <errno.h>并使用errno宏,就好像它是一个全局变量,但知道它实际上不是一个。

Details are implementation specific. 细节是特定于实现的。 Look inside the source code of your C standard library, eg musl-libc has in errno/__errno_location.c 查看C标准库的源代码,例如musl-libcerrno / __ errno_location.c中

  int *__errno_location(void)
  {
     return &__pthread_self()->errno_val;
  }

and in include/errno.h public header: 并在include / errno.h公共标题中:

 int *__errno_location(void);
 #define errno (*__errno_location())

and GNU libc has something very similar 和GNU libc有一些非常相似的东西

BTW some system functions do not return an integer (eg mmap ), and some POSIX functions don't indicate errors thru errno , eg dlopen (see dlerror ). BTW一些​​系统函数不返回整数(例如mmap ),并且一些POSIX函数不指示错误通过errno ,例如dlopen (参见dlerror )。 So it would be difficult to guarantee in some standard that every error could be indicated by returned values. 因此,在某些标准中很难保证每个错误都可以由返回值指示。

I'll cite Linus Torvalds for this. 我会引用Linus Torvalds的话。

"errno" is one of those few really bad stupidities in UNIX. “错误号”在UNIX那几个非常糟糕愚蠢的一个。 Linux has fixed it, and doesn't use it internally, and never shall. Linux修复了它,并没有在内部使用它,也永远不会。 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”愚蠢以实现向后兼容性。

[...] [...]

"errno" is one of those fundamentally broken things that should not exist. “errno”是那些根本不应该存在的破碎事物之一。 It was wrong in original UNIX, it's wrong now. 原来的UNIX是错的,现在错了。

[...] [...]

The Linux way of returning negative error numbers is much nicer. Linux返回负错误号的方法要好得多。 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. 当然,它确实依赖于拥有足够的结果域,您可以始终将错误返回与良好的返回分开,但在实践中对所有系统调用都是如此。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM