在通常情况下, 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
机制的好处? 如果是的话,我想知道/其他的事情,我也可以使用这种机制。
由于fopen
返回一个FILE*
你不能指望它在该指针中返回一个错误代码:指针唯一的“特殊”值是0
。
正如你所观察到的,对于open
这个限制不成立。 事实上,像linux这样的系统完全按照你在低层提出的建议。 如果出现问题,系统调用时会返回负面的错误代码。 然后,这个(否定的)代码被一个浅的用户空间包装器插入到errno
,然后返回-1
来向应用程序指示错误。
这样做的原因纯粹是历史的。 在过去的好时代,没有线程, errno
还只是一个简单的全局变量。 那时选择的策略没有太多的开销,可能似乎是一个可以接受的操作系统和应用程序之间的沟通方式。 由于这样的接口基本上不能被改变,而不会破坏大量的代码,所以我们会将errno
作为线程本地的伪变量。
这并不理想,但是开销并不像听起来那么糟糕,因为这些显然是错误指示,应该只是出现异常情况。
对我来说,获取错误信息的好处是统一的,返回一个负值将open
工作正常,因为它返回一个整数,但是fopen
返回一个FILE *
所以另一个技术将不得不在那里使用。
errno
是一个错误代码。 将错误映射到实际发生的情况非常重要,因此您可以在代码中做出关于下一步做什么的战略决策。 例如,在errno.h
定义的ERANGE
会告诉你strtol("0xfffffffff",NULL,0)
的结果超出了该函数的范围。 更重要的是在你的例子中,知道你是否有EACCES
或EPERM
错误是很好的,所以你知道如何处理这个文件。
你不能映射所有的问题与一个错误代码,因为你可能有多个问题,你想赶上和处理。 当我说赶上,我不是说试试看。
errno的使用建立和错误处理机制,所以你得到更多的信息,而不仅仅是-1。
ERANGE,EACCES,EPERM和其他被认为是为了方便起见映射到特定错误编号的宏。
为每个函数提供一组不同的返回值使得以通用的方式编写代码变得非常复杂。 用目前的语义,你可以采用通用模式:
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);