通常情况下open()
返回新文件描述符,如果发生错误则返回-1,在这种情况下,errno
被适当设置。
我不明白为什么在这里使用errno
的这种机制?什么是这里的目的?为什么我们不能用一些否定的回报来映射所有错误?
喜欢
fd = open("/dev/tty0", O_RDWR | O_SYNC);
if(fd == -1)
printf("this is EACCES error");
else if (fd == -2)
printf("this is EPERM error");
是否有errno
机制的优点?如果是,那么我想知道/理解然后在其他事情我也可以使用这种机制。
答案 0 :(得分:13)
由于fopen
返回FILE*
,你不能指望它在该指针中返回错误代码:指针的唯一“特殊”值是0
。
正如您所观察到的那样,open
这种限制并不成立。事实上,作为linux的系统完全按照你在低级别提出的建议。如果出现问题,系统调用将返回负面错误代码。那个(否定的)代码然后由浅用户空间包装器插入errno
,然后返回-1
以向应用程序指示错误。
这样做的原因纯粹是历史性的。在过去很久没有线程,errno
仍然只是一个简单的全局变量。那时所选择的策略没有太大的开销,并且似乎是在OS和应用程序之间进行通信的可接受方式。由于这些接口基本上不能在不破坏大量代码的情况下进行更改,因此我们将使用errno
作为线程本地的伪变量。
这并不理想,但开销并不像听起来那么糟糕,因为这些显然只是异常发生的错误指示。
答案 1 :(得分:9)
对我来说,优点是以这种方式统一获取错误信息,返回一些负值可以正常使用open
,因为它返回一个整数,但fopen
返回FILE *
所以必须在那里使用另一种技术。
答案 2 :(得分:1)
errno
是错误代码。将错误映射到实际发生的事情非常重要,这样您就可以在代码中做出关于下一步做什么的战略决策。例如,ERANGE
中定义的errno.h
会告诉您strtol("0xfffffffff",NULL,0)
的结果超出了该函数的范围。更重要的是,在您的示例中,最好知道您是否有EACCES
或EPERM
错误,因此您知道如何处理该文件。
您无法使用一个错误代码映射所有问题,因为您可能有多个问题需要捕获和处理。当我说抓住时,我不是指尝试/捕获。
使用errno建立和错误处理机制,因此您获得的信息不仅仅是-1。
为了方便起见,ERANGE,EACCES,EPERM和其他人被认为是映射到特定错误号的宏。答案 3 :(得分:1)
为每个函数提供一组不同的返回值会使以通用方式编写代码变得过于复杂。使用当前语义,您可以采用通用模式:
int fd;
if ((fd = some_function(arg1, arg2)) == -1)
{
perror("some_function");
exit(1);
}
您甚至可以将其包装在宏中:
#define CALL_OR_DIE(function, ret, ...) \
if ((ret = function(__VA_ARGS__)) == -1) \
{ perror(#function); exit(1); }
用法:
int fd;
CALL_OR_DIE(open, fd, "/dev/tty0", O_RDWR | O_SYNC);