The fopen
function may, but might not, set errno
to indicate the specific cause of failure. If it doesn't, then the cause is likely not detectable, or you're dealing with a very poor implementation of the standard library.
Why wouldn't the implementor of fopen
not set errno
, the standard C error-cause-reporting mechanism, unless for some reason it were difficult, or couldn't be done at all? If fopen
can determine a specific cause for why the file cannot be opened, it's as simple matter to set errno
to some value. If this is so hard that the C library implementor ducks out of it, it's probably not going to be easy for you, either, on that platform.
Because fopen
might not set errno
(ISO C doesn't require it), this creates an ambiguity: if fopen
fails, and errno
is nonzero, we don't know whether fopen
set that value, or whether it was already nonzero. The solution is: assign zero to errno before trying fopen.
Tip: if you're working in an older dialect of C, or in a style which avoids mixed declarations and statements, you can still do this with a comma expression:
FILE *f = (errno = 0, fopen(...));
the value and type of the comma expression is that of the right operand.
Then, in the case that fopen
fails, test whether errno
has changed to nonzero. If so, it probably contains information pertaining to the fopen
. You can make an error message more informative, or take some special actions:
if (fp == NULL) {
if (errno != 0)
fprintf(stderr, "Could not open input file, for this reason: %s\n!",
strerror(errno));
else
fprintf(stderr, "Could not open input file, for some reason.\n");
}
Tip: you can use #ifdef
to see whether specific errno
constants exist. For instance if you want to check for and do something special for the POSIX EPERM
, wrap that code with #ifdef EPERM ... #endif
.
Note that the above errno
approach works fine on Microsoft Windows using the MSVCRT (Microsoft Visual C Run Time) C library (no Unix emulation layer). Microsoft's fopen
nicely sets errno
to 2, and the strerror
string for that is "No such file or directory"
. This 2 corresponds to the ENOENT
constant, which Microsoft provides. EPERM
is there and has value 1. The behavior of setting errno
is documented; the following quote is straight out of MSDN: "[i]f an error occurs, the global variable errno is set and may be used to obtain specific error information."
Microsoft's fopen
will also fail and set errno
to EINVAL
if you pass it null strings, and the invalid parameter handler is configured to allow execution to proceed.