C
Chris Torek
[regarding using strerror(errno) or equivalent to expand on
something like "fopen failed", despite the C Standard not
promising that fopen failure must set errno appropriately]
Indeed.
In the past, I have suggested -- and will continue to suggest --
that if you cannot depend on the implementation to go "above
and beyond" the Standard C requirements, you can do something
like this:
/* optional: errno = 0; */
fp = fopen(path, mode);
if (fp == NULL) {
fprintf(stderr, "unable to open %s; most recent system error was %s\n",
path, strerror(errno));
... do whatever else is appropriate here ...
}
In this case, you might get (using a slightly different format):
prog: can't open foo.txt for reading;
most recent system error was "no such process"
on a "bad" system, and:
prog: can't open foo.txt for reading;
most recent system error was "too many open files"
on a "good" system. (And in fact, some pre-POSIX Unix-based systems
*would* fail to set errno if you had the maximum number of files
-- 20 -- open, so that the stdio routines in the C library ran out
of "FILE" objects and never made any system calls. If you were to
set errno to 0 before calling fopen(), strerror(errno) would be
"no error" or "success" or similar.)
In this particular case, I would have been happy to see the C
standards require fopen(), malloc(), and other such functions to
set errno on failure (ideally, C89 and C99 both, but any upgrade
along the way would have been welcome). But we must make do with
what we have.
something like "fopen failed", despite the C Standard not
promising that fopen failure must set errno appropriately]
We're not talking about a failure here, we're talking about
the quality of an error message. On a good implementation,
perror() will generate a reasonable error message. On
a poor implementation, the error messsage will be less
helpful.
Indeed.
In the past, I have suggested -- and will continue to suggest --
that if you cannot depend on the implementation to go "above
and beyond" the Standard C requirements, you can do something
like this:
/* optional: errno = 0; */
fp = fopen(path, mode);
if (fp == NULL) {
fprintf(stderr, "unable to open %s; most recent system error was %s\n",
path, strerror(errno));
... do whatever else is appropriate here ...
}
Is it any more helpful to output:
"operation failed, and this implementation is so broken
that I can't tell you why." than it is to output a message
based on an incorrect value of errno? (well, yeah, I
guess it is...but not by much.)
In this case, you might get (using a slightly different format):
prog: can't open foo.txt for reading;
most recent system error was "no such process"
on a "bad" system, and:
prog: can't open foo.txt for reading;
most recent system error was "too many open files"
on a "good" system. (And in fact, some pre-POSIX Unix-based systems
*would* fail to set errno if you had the maximum number of files
-- 20 -- open, so that the stdio routines in the C library ran out
of "FILE" objects and never made any system calls. If you were to
set errno to 0 before calling fopen(), strerror(errno) would be
"no error" or "success" or similar.)
I suppose I'll raise my standards and make a point
to only claim POSIX conformance for my code. Time
to remove -ansi from CFLAGS, I guess...
In this particular case, I would have been happy to see the C
standards require fopen(), malloc(), and other such functions to
set errno on failure (ideally, C89 and C99 both, but any upgrade
along the way would have been welcome). But we must make do with
what we have.