为啥返回一个负的errno? (例如,返回 -EIO)
Posted
技术标签:
【中文标题】为啥返回一个负的errno? (例如,返回 -EIO)【英文标题】:Why return a negative errno? (e.g. return -EIO)为什么返回一个负的errno? (例如,返回 -EIO) 【发布时间】:2010-12-23 08:28:46 【问题描述】:另一个简单的例子:
if (wpa_s->mlme.ssid_len == 0)
return -EINVAL;
为什么是一元减号?这(通常)是为成功返回 >0 而失败返回
【问题讨论】:
因为我们不喜欢成功! 我不明白为什么人们会在问题标题中添加标签“[C]”。每个问题总是链接它的标签是什么(例如,问题当前被标记为 [c]、[errno]、[return-value]。为什么你没有将问题命名为“[C] [errno] [return-value] 为什么返回一个负的errno?(例如return -EIO)”??? 我看了题目的标题,立刻就抽搐起来,接着是深度昏迷。如果我的工作场所没有一个由世界级脑外科医生组成的快速反应团队,谁知道我是否能及时康复来回答这个问题? 我把语言放在标题中是因为人们,至少对我来说,在查看问题列表时更容易发现它,尽管它也在标签列表中。跨度> 标签对我来说已经足够了,所以会用我感兴趣的标签突出显示消息。“[C]”对我来说只是嘈杂(但我尊重你的口味,不会编辑标题:)) 【参考方案1】:首先,这并不是真正的 C 语言。您正在查看一个出于某种目的而用 C 语言编写的函数。任何语言都可以使用相同的约定。
在我以前的 Unix 时代,有一种约定,即 0 表示成功,正数表示小问题,负数表示某种失败。因此,还有一种if (foo() >= 0) /* success of a sort */
的约定。
这无疑与 Unix 进程返回码有关,其中 0 表示成功。
【讨论】:
在类似问题上引用了你Unix&Linux:"What does exit 99 means?"【参考方案2】:这基本上是原因。很多函数都有很多“好”的正面结果,因此留下了错误代码的负值。
C / POSIX 错误代码有点“历史悠久”,因此尝试将过多的押韵或理由归咎于它们没有多大意义。
许多更现代的语言会为错误抛出异常,这样它们就不必劫持部分可能的错误代码响应范围。当然,无论哪种方式都需要权衡取舍。
【讨论】:
至少曾经有一种倾向,将 0 定义为成功,积极地定义为成功解决问题,消极地定义为不成功——至少在我以前的 Unix 时代是如此。【参考方案3】:您的理解大体上是正确的。显而易见的解释是正确的。
不过,标准约定与您的公式略有不同。
在 Unix 中,以 0 状态退出的程序对 shell 等 CLI 级实用程序测试为 true 或 success。在库中,-1
通常是错误返回。
这导致了一个通用范式,其中>= 0
表示良好,< 0
表示错误。这些都不是一成不变的。
顺便说一句,这可能被归类为 sentinel pattern,您可以将其称为 哨兵返回。哨兵“值”和错误代码,与在一个地方返回错误代码并在另一个地方返回错误的哨兵值相比,它更容易键入并且更容易使线程安全。
Wikipedia reports that a sentinel value 用于终止循环,但我认为函数返回将是一个更常见的实例。没有人确切地负责这些定义。
【讨论】:
【参考方案4】:从优化的角度来看,使用负数允许基于 Unix 的内核仅使用一次比较而不是两次比较来检查错误代码。
内核中的函数经常返回错误代码而不是指针。这意味着错误代码不能与有效的指针地址重叠,因此它们基本上必须是最低的无符号值(>= 0)
或最高的(<= unsigned max)
。
检查NULL
和错误代码的指针值是非常常见的操作,因此对其进行优化是有意义的。
通常,底部值 < 0x8000
是 NULL
,顶部值是错误代码(请记住,-1
存储为 0xff...ff
,最大可能的无符号值)。
这意味着您可以使用一个比较来检查每个:
NULL
if x <= 0x8000
(0 到 0x8000 为真)
ERRNO
if x >= (unsigned long)(-MAX_ERRNO)
(-1 到 -MAX_ERRNO 为真)
You can see this happening in Linux's err.h file.
【讨论】:
这是对 Linux 内核问题的最佳答案。以上是关于为啥返回一个负的errno? (例如,返回 -EIO)的主要内容,如果未能解决你的问题,请参考以下文章
“epoll errno (EINTR)4” —— epoll遭遇EINTR(Interrupted system call)