C
Chris Torek
... The error messages will [with the above line of code] include
the pathname of the file that caused the error, and that information
can be hugely helpful to understanding a problem. "FOPEN: permission
denied" is much less informative than "/etc/passwd: permission
denied".[/QUOTE]
I prefer the even-more-detailed form:
progname: cannot open /etc/passwd for writing: Permission denied.
which one can obtain with, e.g.:
if ((fp = fopen(filepath, "w")) == NULL) {
fprintf(stderr, "%s: cannot open %s for %s: %s\n",
progname, filepath, "writing", strerror(errno));
... additional action here as needed ...
}
The above version requires even more work, of course: you must
also record the program-name somewhere. (If the open-or-fail
routine is a subroutine, it is best not to hard-code the program
name, so that the subroutine is reuseable.)
If you wish to protect against implementations that fail to set
errno in fopen, you can even do things like:
FILE *open_file_or_die(const char *filepath, const char *mode) {
FILE *fp;
errno = 0;
if ((fp = fopen(filepath, mode)) == NULL) {
char *mode_as_verb = (*mode == 'r') ? "reading" : "writing";
char *err = errno ? strerror(errno) : "no system error reported";
fprintf(stderr, "%s: cannot open %s for %s: %s\n",
progname, filepath, mode_as_verb, err);
exit(EXIT_FAILURE); /* or abort(), perhaps */
}
return fp;
}
and/or you can use text like "last system error reported" to
mark the string returned by strerror(errno).
(It is tempting to make the "verb" be "read" or "writ" and put
the "ing" into the format string. This works well enough in
English, but if you ever decide to have the error messages
get translated into other languages, maybe not so well anymore.)
the pathname of the file that caused the error, and that information
can be hugely helpful to understanding a problem. "FOPEN: permission
denied" is much less informative than "/etc/passwd: permission
denied".[/QUOTE]
I prefer the even-more-detailed form:
progname: cannot open /etc/passwd for writing: Permission denied.
which one can obtain with, e.g.:
if ((fp = fopen(filepath, "w")) == NULL) {
fprintf(stderr, "%s: cannot open %s for %s: %s\n",
progname, filepath, "writing", strerror(errno));
... additional action here as needed ...
}
It is a design choice; it does require extra work to keep
track of the path names in order to report them, and I am suggesting
that it is worth the effort.
The above version requires even more work, of course: you must
also record the program-name somewhere. (If the open-or-fail
routine is a subroutine, it is best not to hard-code the program
name, so that the subroutine is reuseable.)
If you wish to protect against implementations that fail to set
errno in fopen, you can even do things like:
FILE *open_file_or_die(const char *filepath, const char *mode) {
FILE *fp;
errno = 0;
if ((fp = fopen(filepath, mode)) == NULL) {
char *mode_as_verb = (*mode == 'r') ? "reading" : "writing";
char *err = errno ? strerror(errno) : "no system error reported";
fprintf(stderr, "%s: cannot open %s for %s: %s\n",
progname, filepath, mode_as_verb, err);
exit(EXIT_FAILURE); /* or abort(), perhaps */
}
return fp;
}
and/or you can use text like "last system error reported" to
mark the string returned by strerror(errno).
(It is tempting to make the "verb" be "read" or "writ" and put
the "ing" into the format string. This works well enough in
English, but if you ever decide to have the error messages
get translated into other languages, maybe not so well anymore.)