C 当POSIX函数返回-1或NULL指示错误条件时,为什么会出现errno
当其中一个UNIX系统函数发生错误时,通常会返回负值,并将整数C 当POSIX函数返回-1或NULL指示错误条件时,为什么会出现errno,c,posix,errno,C,Posix,Errno,当其中一个UNIX系统函数发生错误时,通常会返回负值,并将整数errno设置为一个值,该值提供了附加信息。 --UNIX环境中的高级编程,第1.7节 这似乎很奇怪: 它引入了标准库的不同编译单元之间的耦合——导致错误的模块中没有定义错误状态 它引入了实现复杂性,因为errno需要是线程本地的 它引入了可用性复杂性,因为用户需要检查原始系统调用是否有错误,然后检查errno,这也是另一个函数调用 为什么不在返回值中对错误状态进行编码?主要是出于历史原因 请注意,在现实中,errno现在不是一个
errno
设置为一个值,该值提供了附加信息。
--UNIX环境中的高级编程,第1.7节
这似乎很奇怪:
- 它引入了标准库的不同编译单元之间的耦合——导致错误的模块中没有定义错误状态
- 它引入了实现复杂性,因为
需要是线程本地的errno
- 它引入了可用性复杂性,因为用户需要检查原始系统调用是否有错误,然后检查
,这也是另一个函数调用errno
为什么不在返回值中对错误状态进行编码?主要是出于历史原因 请注意,在现实中,
errno
现在不是一个普通的全局变量(20世纪80年代就是这种情况)。现在(C99,C11…)是一个宏-通常扩展为一些函数调用,可能是\uu errno()
(最近的C标准要求errno
是一个宏,请参见§7.5);或者它可能被扩展到一些线程局部变量,甚至一些编译器魔术
errno
希望成为满足多线程需求的宏,所以我猜标准的发展要求它是某种宏
因此,您应该#包括
并使用errno
宏,就像它是某个全局变量一样,但要知道事实上它不是一个全局变量
细节是具体实施的。查看C标准库的源代码,例如
在公共标题中:
int *__errno_location(void);
#define errno (*__errno_location())
GNULIBC也有相似之处
顺便说一句,有些系统函数不返回整数(例如mmap
),有些POSIX函数不通过errno
指示错误,例如dlopen
(请参见dlerror
)。因此,在某些标准中,很难保证每个错误都可以由返回值表示。我将对此进行详细说明
“errno”是UNIX中为数不多的几个非常糟糕的愚蠢行为之一。Linux已经
已修复,不在内部使用,永远不会。太糟糕了
用户空间必须修复正确的错误代码,返回
内核会这样做,并将其转化为向后的“errno”愚蠢
兼容性
[……]
“厄尔诺”是那些根本不应该发生的事情之一
存在。它在最初的UNIX中是错误的,现在是错误的
[……]
Linux返回负错误数的方法要好得多。它是
本质上是线程安全的,并且它没有性能方面的缺点。当然,它
这取决于是否有足够的结果域
将错误返回与良好返回分开,但对于
所有系统调用
假设这种机制是在线程之前发明的,这是非常安全的。另外,为了有点迂腐,检查
errno
不一定是函数调用。而且,函数返回值在许多情况下用于返回实际数据。请参阅。read()
是一个不好的示例,特别是在这里返回-errno
是可行的,假设它返回的是一个有符号的
整数,而它不返回@AndrewHenle@alk当然返回ssize\u t
,即size\u t
的签名表亲?@alk-OK,但错误代码通常不能与有效返回值分离的观点仍然成立。要求errno
必须是宏,禁止或隐藏宏是未定义的行为。@AndrewHenle:那又怎样?@alkerrno
始终是宏。目前,它的资格是“非常经常”。考虑到答案的作者是谁,我强烈怀疑他的目的是完全正确。啊,我明白了。很公平@AndrewHenle@AndrewHenle:我改进了我的答案,并把“作者是谁”作为一种恭维。。。
int *__errno_location(void);
#define errno (*__errno_location())