How to check the value of errno
:
- You will need to
#include <errno.h>
.
- Yes, you can definitely say things like
if(errno == ENOENT) { ... }
, and that is the common and recommended way of doing it.
- In general, do not use
errno
to determine that an error has occurred. Check the return value of the function, and if the return value indicates an error, then check errno
to see what the error was. (More on this below.)
errno
looks like a variable, but it actually isn't. This doesn't concern you as long as you just say things like if(errno == ENOENT) { ... }
. But you probably shouldn't try to do something like int errno_ptr = &errno;
.
- You can use functions like
perror()
and strerror()
to get human-readable error strings corresponding to errno
values. But, yes, the strings you get are generally things like "No such file or directory". There is no good way that I know of to convert the errno value ENOENT
to the string "ENOENT"
.
To say a little more about #3. Sometimes it's tempting to say something like
errno = 0;
printf("Hello, world!
");
if(errno != 0) {
fprintf(stderr, "printf failed!
");
}
But don't do that. Instead do
errno = 0;
int retval = printf("Hello, world!
");
if(retval < 0) {
fprintf(stderr, "printf failed!
");
}
The reason is that, somewhere in the process of doing its job, printf
might have done something that resulted in an error, something that set errno
, but printf
might have recovered from that error and gone on to complete successfully.
There are a very few library functions that are guaranteed not to touch errno if there wasn't an error (I think one example might be atoi
), but in general, this is something you have to be careful of.
To say a little more about #4. errno
looks like a variable, and more specifically, it looks like a global variable. But of course global variables are bad. But errno
has been around forever; there are tens of millions of lines of code that use it; it's still basically pretty convenient; it's too late to "fix" it. So, instead, if you peek behind the curtain, you'll find that most implementations do something like
extern int __errno_pointer;
#define errno (*__errno_pointer)
or
extern int *__errno_pointer_function();
#define errno (*__errno_function())
In this way, they can arrange for errno
to work reasonably properly even in, say, multithreaded code.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…