fgetc(): Is it enough to just check EOF?

2019-01-15 18:40发布

问题:

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?

回答1:

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);


回答2:

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.



回答3:

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 =.



标签: c file-io