简体   繁体   中英

Regarding errno and strerror()

Considering fopen() fails, in the following piece of code:

FILE *fp = fopen("file.txt", "w");
if (fp == NULL) {
    printf("Error occurred while opening file, errno=%d, %s\n", 
                         errno, strerror(errno));
    exit(1);
}

Since the order in which function arguments are evaluated is unspecified in C, while invoking printf() , in case call to strerror() is evaluated (invoked) first and it fails, wouldn't errno be set to something else when the line actually gets printed? Or, is it that errno would have been copied into the activation record of printf() even before evaluating strerror() and hence would remain unchanged? Is this unspecified behaviour?

EDIT: Yes, I do understand that I can save errno to some int right after fopen() , but that's not my point here. I am trying to figure out how the above piece of code behaves.

Since no return value is reserved to indicate an error, an application wishing to check for error situations should set errno to 0, then call strerror(), then check errno.

From the same article that you used. Very likely it's unspecified behaviour. MAN tells the same

POSIX.1-2001 and POSIX.1-2008 require that a successful call to strerror() or strerror_l() shall leave errno unchanged, and note that, since no function return value is reserved to indicate an error, an application that wishes to check for errors should initialize errno to zero before the call, and then check errno after the call.

So you can save errno of fopen , and then get errno of strerror . Or simply use perror .

Considering fopen fails, in the following piece of code:

 FILE *fp = fopen("file.txt", "w"); if (fp == NULL) { printf("Error occurred while opening file, errno=%d, %s\n", errno, strerror(errno)); exit(1); }

Since the order in which function arguments are evaluated is unspecified in C, while invoking printf , in case call to strerror is evaluated (invoked) first and it fails, wouldn't errno be set to something else when the line actually gets printed?

That is indeed possible. Additionally, according to the C standard, errno could be set to a nonzero value whether or not there is an error in the call to strerror or any other library function provided the use of errno is not documented for the function (see C17 7.5/3). However, POSIX (since POSIX.1-2001, and prior to that in 1997's Single UNIX Specification, version 2) guarantees that strerror will not change the setting of errno if successful.

Or, is it that errno would have been copied into the activation record of printf even before evaluating strerrno() and hence would remain unchanged? Is this unspecified behaviour?

It is unspecified behaviour. The arguments and function designator can be evaluated in any order (but there is a sequence point before the actual call to the function to avoid evaluations within a function body being interleaved with evaluations within another function body) (see C17 6.5.2.2/10).

This is an issue that could occur under Linux as the manual of strerror() says in the NOTES section that errno can be modified by the service:

POSIX.1-2001 permits strerror() to set errno if the call encounters an error, but does not specify what value should be returned as the function result in the event of an error. On some systems, strerror() returns NULL if the error number is unknown. On other systems, strerror() returns a string something like "Error nnn occurred" and sets errno to EINVAL if the error number is unknown. C99 and POSIX.1-2008 require the return value to be non-NULL.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM