Error handling in file opening
Re Q1:
a) Most POSIX functions actually return -1 (or <0) for errors, not 0. Look at (for instance) open()
, close()
, read()
, write()
and so forth. The exception is the POSIX calls that return pointers, e.g. fopen()
, which returns a FILE *
. These return NULL
on error.
b) I code my code to work like POSIX functions, which is similar the innards of many linux programs. I would call this 'the UNIX C standard'. However, many C++ programs and Java programs use true
for success and false
for failure. When these programmers move to C, they use 1 for success, and 0 for failure. This isn't wrong, but does cause confusion (well, causes me confusion). The worst result is when both standards are used in the same program. Picking a standard and sticking to it is more important than which standard you choose.
c) My own choice (in relation to Q1), would be to return -1
on error (i.e. as per your 'another choice' line).
Re Q2: mostly right, yes.
a) If your program is successful, better to exit(0)
than return 0
I believe.
b) Quite where you perror
is up to you. Perhaps you want to print the error in main()
.
c) Using perror
immediately followed by exit(1)
(or perhaps a different exit code depending on the error) is reasonable normal if you have no clean up to do or clean up within atexit
.
d) If you are returning the result of fclose()
on error, then the return if fopen
fails should be -1
(or EOF
) not 1 as if fclose()
fails it returns EOF
(otherwise known as -1
).
e) Nit: your main
function should have parameters (e.g. int main(char **argv, int argc)
)
ᴜsᴇʀ
Updated on January 22, 2020Comments
-
ᴜsᴇʀ over 4 years
[Question 1]
When I open a file into a function, generally I do something like this:
int read_file (char *filename) { FILE *fin; if ( !(fin = fopen(filename, "r")) ) return 1; /* ... */ return fclose(fin); } int main () { char filename[100]; if ( read_file(filename) ) { perror(filename); exit(1); } return 0; }
Generally
0
return value is for errors (right?) then I can change the previous code into:int read_file (char *filename) { FILE *fin; if ( !(fin = fopen(filename, "r")) ) return 0; /* ... */ return !fclose(fin); } int main () { char filename[100]; if ( !read_file(filename) ) { perror(filename); exit(1); } return 0; }
But I think that the first code is more clean.
Another option is only change
return 1;
intoreturn -1;
(in the first code that I wrote).What's the best version?
[Question 2]
If I must handle more errors, is it correct a code like this?
int read_file (char *filename, int **vet) { FILE *fin; if ( !(fin = fopen(filename, "r")) ) { perror(filename); return 1; } * vet = malloc (10 * sizeof(int)); if ( *vet == NULL ) { perror("Memory allocation error.\n"); return 1; } /* ... */ return fclose(fin); } int main () { char filename[100]; int *vet; if ( read_file(filename, &vet) ) exit(1); return 0; }
-
ᴜsᴇʀ over 10 years(Q2b) "Quite where you
perror
is up to you. Perhaps you want to print the error inmain()
." But if I useperror
intomain()
I can't differentiate the errors! (Q2d) "If you are returning the result offclose()
on error, then the return iffopen
fails should be-1
(orEOF
) not 1 as iffclose()
fails it returnsEOF
(otherwise known as-1
)." But iffopen
fails it returns tomain()
: it not arrive until thefclose()
. -
ᴜsᴇʀ over 10 years(Q2e) "Nit: your main function should have parameters (e.g.
int main(char **argv, int argc))
" If you don't use themain()
parameters you can not write them. From Standard documents 3.6.1.2 Main Function: "It shall have a return type of type int, but otherwise its type is implementation-defined. All implementations shall allow both of the following definitions of main:int main() { / ... / }
andint main(int argc, char* argv[]) { / ... / }
"