According to man page fclose(3)
:
RETURN VALUE
Upon successful completion 0 is returned. Otherwise,
EOF
is returned and the global variableerrno
is set to indicate the error. In either case any further access (including another call tofclose()
) to the stream results in undefined behavior.ERRORS
EBADF
The file descriptor underlyingfp
is not valid.The
fclose()
function may also fail and seterrno
for any of the errors specified for the routinesclose(2)
,write(2)
orfflush(3)
.
Of course fclose(NULL)
should fail but I expect that it to return with an errno
normally instead of dying by segmentation fault directly. Is there any reason of this behavior?
Thanks in advance.
UPDATE: I shall put my code here (I'm trying strerror()
, particularly).
FILE *not_exist = NULL;
not_exist = fopen("nonexist", "r");
if(not_exist == NULL){
printError(errno);
}
if(fclose(not_exist) == EOF){
printError(errno);
}
fclose
requires as its argument a FILE
pointer obtained either by fopen
, one of the standard streams stdin
, stdout
, or stderr
, or in some other implementation-defined way. A null pointer is not one of these, so the behavior is undefined, just like fclose((FILE *)0xdeadbeef)
would be. NULL is not special in C; aside from the fact that it's guaranteed to compare not-equal to any valid pointer, it's just like any other invalid pointer, and using it invokes undefined behavior except when the interface you're passing it to documents as part of its contract that NULL
has some special meaning to it.
Further, returning with an error would be valid (since the behavior is undefined anyway) but harmful behavior for an implementation, because it hides the undefined behavior. The preferable result of invoking undefined behavior is always a crash, because it highlights the error and enables you to fix it. Most users of fclose
do not check for an error return value, and I'd wager that most people foolish enough to be passing NULL
to fclose
are not going to be smart enough to check the return value of fclose
. An argument could be made that people should check the return value of fclose
in general, since the final flush could fail, but this is not necessary for files that are opened only for reading, or if fflush
was called manually before fclose
(which is a smarter idiom anyway because it's easier to handle the error while you still have the file open).