为什么要使用'errno'呢?

时间:2011-05-15 08:24:49

标签: c std

我是以色列理工学院的cs学生,我刚刚学会了'errno'变量和c风格的函数。呼叫。 这让我想知道,如果c风格的系统调用使用寄存器来返回值,为什么有人会使用'errno'呢?

4 个答案:

答案 0 :(得分:8)

使用errno的主要原因是提供有关错误情况的更多信息。

这在函数的大多数(甚至所有)可能的返回值实际上是有效返回值的情况下特别有用。

考虑fopen()函数,该函数返回指向FILE的指针。除NULL外,每个可能的返回值也是有效的返回值。因此fopen()失败时返回NULL。但是你无法确定究竟是什么让这个功能失败了。因此,fopen()使用errno表示确切的错误条件,即文件不存在,或者您没有读取它的权限,或者系统内存不足等等。

您可以将errno视为一个全局变量(它曾经是线程变得流行之前)。如今,errno通常是一个包含函数调用的宏,返回错误条件。但这只是C实现特定于线程的全局变量的方式。

errno的替代方案不太舒服:

你可以提供一个带有int指针的函数,该函数可以在那里存储它的错误条件。 strtod()就是这种技术的一个很好的例子。但这使得API更加复杂,因此不太理想。此外,它强制程序员定义一个新的int,如果您不关心函数是否失败,这很烦人。

在允许多个返回值(并且不包含异常)的语言中,通常返回两个值:一个用于实际结果,另一个用于表示错误条件。在Go等语言中,您会看到如下代码:

result, ok = foo();
if (ok) {
    // handle error denoted by "ok"
}

不要相信那些声称errno是“旧”技术并因此被避免的人。您正在编程的机器远远超过errno甚至C,并且没有人抱怨过。

答案 1 :(得分:6)

C库的设计很久以前就像早期的Unix一样。使用单独的错误代码并不是一种不常见的模式(Win32具有类似的GetLastError())。它具有表面优势。

如果您希望某类函数具有常用的返回值,则无法轻松使用该函数返回错误。例如,假设一个假设的API

mytime_t t = get_current_time();

此API的常见用途是获取时间。但也许它可能在某些情况下失败,并且您从errno获得详细的错误信息。这使得API代码比您不得不说

更容易阅读和编写
mytime_t t=0;
errno_t e = get_current_time(&t);

从表面上看,错误型系统很有吸引力。但是,错误状态与实际函数调用的分离会导致许多问题。现代环境使errno_t成为每线程变量(消除最明显的问题来源),但你仍然面临着如果你做的问题

mytime_t t = get_current_time();
mysize_t s = get_window_size();

然后你无形地从第一个函数中破坏errno。当代码可以在错误路径中运行或者其中一个函数以其他方式实现时,这会变得更加复杂。大量保存和恢复errno值可确保。我认为现在这种系统很脆弱且不受欢迎。

许多人使用在显式参数/返回集之外携带错误的异常(许多C ++程序员做出这个选择)。在无异常语言或环境中工作的人往往会咬紧牙关并保留错误的返回值,并始终通过参数提供输出(COM使用HRESULT进行此选择)。

答案 2 :(得分:2)

我能想到的最好的例子是stdio函数fopen,它在失败时返回NULL,找出失败原因的唯一方法是通过errno和/或perror。

必须有其他例子。这正是目前涌现的想法。

答案 3 :(得分:2)

errno是一件复杂的事情,因为它是一个历史性的界面,现在可能没人会这样设计。此外,在大多数系统中,它现在看起来只是一个变量,它不是一个变量。通常它被实现为隐藏函数调用的宏,并且该函数调用返回特定于线程的错误条件。