为什么fopen()或open()使用errno而不是只返回错误代码?

时间:2022-05-02 22:33:45

In usual case open() return the new file descriptor, or -1 if an error occurred and in that case, errno is set appropriately.

通常情况下,open()返回新的文件描述符,如果发生错误则返回-1,在这种情况下,正确设置errno。

I am not understanding why this mechanism of errno is used here? whats the purpose of here? why just we can not map all error with some negative return no?

我不明白为什么在这里使用errno的这种机制?什么是这里的目的?为什么我们不能用一些否定的回报映射所有错误?

like

喜欢

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");

Is there any benifit of errno mechanism.? if yes then i would like to know/understand then in other things i can also use this mechanism.

有没有任何errno机制的好处。?如果是,那么我想知道/理解然后在其他事情我也可以使用这种机制。

4 个解决方案

#1


11  

Since fopen returns a FILE* you can't expect it to return an error code in that pointer: the only "special" value for pointers is 0.

由于fopen返回一个FILE *,你不能指望它在该指针中返回一个错误代码:指针的唯一“特殊”值是0。

As you observe, for open this restriction doesn't hold. In fact systems as linux do exactly what you propose in their lower levels. The system call under the hood returns the negative error code if things go wrong. That (negated) code is then plug into errno by a shallow user space wrapper which then returns the -1 to indicate the error to the application.

正如你所看到的那样,对于开放这种限制并不成立。事实上,作为linux的系统完全按照你在较低级别提出的建议。如果出现问题,系统调用将返回负面错误代码。那个(否定的)代码然后由浅用户空间包装器插入到errno中,然后返回-1以向应用程序指示错误。

The reason that this is done so is purely historical. In good old times there was no threading and errno was still just a simple global variable. At that time the chosen strategy incurred not much overhead and probably seemed an acceptable way to communicate between OS and application. Since such interfaces basically can't be changed without breaking a lot of code, we will be stuck with errno as a pseudo variable that is thread local.

这样做的原因纯粹是历史性的。在过去的好时代,没有线程,而errno仍然只是一个简单的全局变量。那时所选择的策略没有太大的开销,并且似乎是在OS和应用程序之间进行通信的可接受方式。由于这些接口基本上不能在不破坏大量代码的情况下进行更改,因此我们将使用errno作为线程本地的伪变量。

This is not ideal, but the overhead is not as bad as it sounds, since these are clearly error indications that should occur only exceptionally.

这并不理想,但开销并不像听起来那么糟糕,因为这些显然是错误指示,只能在特殊情况下发生。

#2


9  

For me the advantage is that getting the error information is unified in that way, returning some negative value would work OK with open as it returns an integer, but fopen returns a FILE * so another technique would have to be used there.

对我来说,优点是以这种方式统一获取错误信息,返回一些负值可以正常工作,因为它返回一个整数,但fopen返回一个FILE *所以必须在那里使用另一种技术。

#3


1  

errno is an error code. It is important to map the errors to what is actually happening so you can make strategic decisions in your code on what to do next. For instance, ERANGE which is defined in errno.h, will tell you that the result of strtol("0xfffffffff",NULL,0) is out of that function's range. More importantly in your example, it is good to know whether you have an EACCES or EPERM error so you know how to handle the file.

errno是一个错误代码。将错误映射到实际发生的情况非常重要,这样您就可以在代码中做出关于下一步做什么的战略决策。例如,在errno.h中定义的ERANGE将告诉您strtol(“0xfffffffff”,NULL,0)的结果超出了该函数的范围。更重要的是,在您的示例中,最好知道您是否有EACCES或EPERM错误,因此您知道如何处理该文件。

You can't map all problems with one error code since you could have multiple issues that you would like to catch and handle. When I say catch, I do not mean try/catch.

您无法使用一个错误代码映射所有问题,因为您可能有多个问题需要捕获和处理。当我说抓住时,我不是指尝试/捕获。

The use of errno establishes and error handling mechanism so you get more information than just -1.

使用errno建立和错误处理机制,因此您获得的信息不仅仅是-1。

ERANGE, EACCES, EPERM, and others are considered macros that map to a particular error number for convenience purposes.

为方便起见,ERANGE,EACCES,EPERM和其他被认为是映射到特定错误号的宏。

#4


1  

Giving each function a distinct set of return values makes it overly complicated to write code in a generic fashion. With the current semantics, you can adopt a universal pattern:

为每个函数提供一组不同的返回值会使以通用方式编写代码变得过于复杂。使用当前语义,您可以采用通用模式:

int fd;
if ((fd = some_function(arg1, arg2)) == -1)
{
    perror("some_function");
    exit(1);
}

You can even wrap this in a macro:

你甚至可以将它包装在一个宏中:

#define CALL_OR_DIE(function, ret, ...)      \
    if ((ret = function(__VA_ARGS__)) == -1) \
    { perror(#function); exit(1); }

Usage:

用法:

int fd;
CALL_OR_DIE(open, fd, "/dev/tty0", O_RDWR | O_SYNC);

#1


11  

Since fopen returns a FILE* you can't expect it to return an error code in that pointer: the only "special" value for pointers is 0.

由于fopen返回一个FILE *,你不能指望它在该指针中返回一个错误代码:指针的唯一“特殊”值是0。

As you observe, for open this restriction doesn't hold. In fact systems as linux do exactly what you propose in their lower levels. The system call under the hood returns the negative error code if things go wrong. That (negated) code is then plug into errno by a shallow user space wrapper which then returns the -1 to indicate the error to the application.

正如你所看到的那样,对于开放这种限制并不成立。事实上,作为linux的系统完全按照你在较低级别提出的建议。如果出现问题,系统调用将返回负面错误代码。那个(否定的)代码然后由浅用户空间包装器插入到errno中,然后返回-1以向应用程序指示错误。

The reason that this is done so is purely historical. In good old times there was no threading and errno was still just a simple global variable. At that time the chosen strategy incurred not much overhead and probably seemed an acceptable way to communicate between OS and application. Since such interfaces basically can't be changed without breaking a lot of code, we will be stuck with errno as a pseudo variable that is thread local.

这样做的原因纯粹是历史性的。在过去的好时代,没有线程,而errno仍然只是一个简单的全局变量。那时所选择的策略没有太大的开销,并且似乎是在OS和应用程序之间进行通信的可接受方式。由于这些接口基本上不能在不破坏大量代码的情况下进行更改,因此我们将使用errno作为线程本地的伪变量。

This is not ideal, but the overhead is not as bad as it sounds, since these are clearly error indications that should occur only exceptionally.

这并不理想,但开销并不像听起来那么糟糕,因为这些显然是错误指示,只能在特殊情况下发生。

#2


9  

For me the advantage is that getting the error information is unified in that way, returning some negative value would work OK with open as it returns an integer, but fopen returns a FILE * so another technique would have to be used there.

对我来说,优点是以这种方式统一获取错误信息,返回一些负值可以正常工作,因为它返回一个整数,但fopen返回一个FILE *所以必须在那里使用另一种技术。

#3


1  

errno is an error code. It is important to map the errors to what is actually happening so you can make strategic decisions in your code on what to do next. For instance, ERANGE which is defined in errno.h, will tell you that the result of strtol("0xfffffffff",NULL,0) is out of that function's range. More importantly in your example, it is good to know whether you have an EACCES or EPERM error so you know how to handle the file.

errno是一个错误代码。将错误映射到实际发生的情况非常重要,这样您就可以在代码中做出关于下一步做什么的战略决策。例如,在errno.h中定义的ERANGE将告诉您strtol(“0xfffffffff”,NULL,0)的结果超出了该函数的范围。更重要的是,在您的示例中,最好知道您是否有EACCES或EPERM错误,因此您知道如何处理该文件。

You can't map all problems with one error code since you could have multiple issues that you would like to catch and handle. When I say catch, I do not mean try/catch.

您无法使用一个错误代码映射所有问题,因为您可能有多个问题需要捕获和处理。当我说抓住时,我不是指尝试/捕获。

The use of errno establishes and error handling mechanism so you get more information than just -1.

使用errno建立和错误处理机制,因此您获得的信息不仅仅是-1。

ERANGE, EACCES, EPERM, and others are considered macros that map to a particular error number for convenience purposes.

为方便起见,ERANGE,EACCES,EPERM和其他被认为是映射到特定错误号的宏。

#4


1  

Giving each function a distinct set of return values makes it overly complicated to write code in a generic fashion. With the current semantics, you can adopt a universal pattern:

为每个函数提供一组不同的返回值会使以通用方式编写代码变得过于复杂。使用当前语义,您可以采用通用模式:

int fd;
if ((fd = some_function(arg1, arg2)) == -1)
{
    perror("some_function");
    exit(1);
}

You can even wrap this in a macro:

你甚至可以将它包装在一个宏中:

#define CALL_OR_DIE(function, ret, ...)      \
    if ((ret = function(__VA_ARGS__)) == -1) \
    { perror(#function); exit(1); }

Usage:

用法:

int fd;
CALL_OR_DIE(open, fd, "/dev/tty0", O_RDWR | O_SYNC);