34

另一个简单的例子:

if (wpa_s->mlme.ssid_len == 0)
    return -EINVAL;

为什么是一元减号?这(通常)是为成功返回 >0 而失败返回 <(=)0 的函数完成的,还是有其他原因?

4

4 回答 4

23

首先,这并不是真正的 C 语言。您正在查看一个出于某种目的而用 C 语言编写的函数。任何语言都可以使用相同的约定。

回到我以前的 Unix 时代,有一种约定,即 0 表示成功,正数表示小问题,负数表示某种失败。因此,也有一种约定if (foo() >= 0) { /* success of a sort */ }

这无疑与 Unix 进程返回码有关,其中 0 表示成功。

于 2009-12-04T18:43:51.280 回答
17

基本就是这个原因。许多函数都有很多“好”的正面结果,因此留下了错误代码的负值。

C / POSIX 错误代码有点“历史悠久”,因此尝试将过多的押韵或理由归咎于它们没有多大意义。

许多更现代的语言为错误抛出异常,因此它们不必劫持部分可能的错误代码响应范围。当然,无论哪种方式都需要权衡取舍。

于 2009-12-04T18:25:19.477 回答
8

你的理解大体上是正确的。显而易见的解释是正确的。

但是,标准约定与您的公式略有不同。

在 Unix 中,以 0 状态退出的程序对 shell 等 CLI 级实用程序测试为成功。在库中,-1通常是错误返回。

这导致了一个一般范式,其中>= 0意味着< 0意味着错误。 这一切都不是一成不变的。

顺便说一句,这可能被归类为哨兵模式,你可以称之为哨兵返回。它实际上是一个标记“值”和一个错误代码的组合,与在一个地方返回错误代码和在另一个地方返回错误的标记值相比,它更容易键入并且更容易使线程安全。

维基百科报告说哨兵值用于终止循环,但我认为函数返回将是一个更常见的实例。没有人确切地负责这些定义。

于 2009-12-04T18:30:08.497 回答
6

从优化的角度来看,使用负数允许基于 Unix 的内核仅使用一次比较而不是两次比较来检查错误代码。

内核中的函数经常返回错误代码来代替指针。这意味着错误代码不能与有效的指针地址重叠,因此它们基本上必须是最低无符号值(>= 0)或最高无符号值(<= unsigned max)

检查指针值NULL和错误代码是非常常见的操作,因此优化它们是有意义的。

通常,底部值< 0x8000NULL错误代码,而顶部值是错误代码(请记住,-1它存储为0xff...ff,最大可能的无符号值)。

这意味着您可以使用一个比较来检查每个:

NULL如果x <= 0x8000(0 到 0x8000 为真)

ERRNOif x >= (unsigned long)(-MAX_ERRNO)(对于 -1 到 -MAX_ERRNO 为真)

您可以在 Linux 的 err.h 文件中看到这种情况。

于 2018-01-04T18:04:52.443 回答