In various examples found on the web fgetc()
is used like this:
FILE *fp = fopen(PATH, "r");
if (fp == NULL) {
perror("main");
exit(EXIT_FAILURE);
}
int ch;
while (ch = fgetc(fp) != EOF) {
// do something
}
But according to the manpage to fgetc()
If a read error occurs, the error
indicator for the stream shall be set,
fgetc() shall return EOF, [CX] and
shall set errno to indicate the error.
So need I check this too? And how?
You can check it with ferror(3), right after the while:
while (EOF != (ch = fgetc(fp)))
// do something
if (ferror(fp) != 0)
// error handling
ferror returns a non-zero if an error occured.
If you want use fp after an error occured, you'll need to clear the error flag with clearerr:
clearerr(fp);
Looping until fgetc
returns EOF
is perfectly fine. Afterwards, if you want to know whether the loop ended due to simply reaching the end of the file or due to an error, you should call ferror
or feof
. If you don't care you can skip the call.
Note that it matters whether you check feof
or ferror
, because the error indicator for a stream is sticky and can evaluate true even when hitting eof was the cause of fgetc
failure. Normally you should use feof
to check, and if it returns false, conclude that the loop stopped due to a new error.
This is what the specs say:
the fgetc() function shall obtain the next byte as an unsigned char converted to an int
The following macro name shall be defined as a negative integer constant expression: EOF
As long as you store the return value in an int
and not a char
, it is sufficient to check for EOF
because it is guaranteed not to represent a valid character value.
Also, in your code, this:
while (ch = fgetc(fp) != EOF)
should be:
while ((ch = fgetc(fp)) != EOF)
The additional parentheses are required because !=
has higher precedence than =
.