Confusion with == EOF vs feof
Asked Answered
C

5

14

I opened a file, the stream is found at the address of pointer ptr. I am attempting to see whether or not a file is blank. Using the following

if (fgetc(ptr) != EOF)

works as expected. When the file is blank, the statement is not executed. When the file is not blank, the statement is not executed.

However, using

if (!feof(ptr))

always executes the statement.

Why does this happen? Is there a way to use the feof function?

Calx answered 22/3, 2016 at 20:38 Comment(2)
The EOF indicator is set after a failed read.Tahr
See Why is “while ( !feof (file) )” always wrong?Knighthood
R
16

Is there a way to use the feof function?

Yes, there is. After an input function has returned a value that indicates that it has no more input to process, you can call feof() and/or ferror() to determine whether the condition was caused by reaching the end of the input or some error condition.

This is the only valid use for the feof() and ferror() functions.

The result that indicates that no more input remains differs from one function to another. For example fgetc() returns the value EOF, fgets() returns a null pointer, and fread() returns some value less than the number of records requested. You need to read the documentation for each input function to see how it works.

Revanchism answered 22/3, 2016 at 20:58 Comment(6)
fread returning less than requested only indicates the equivalent of EOF when 0 was returned.Knighthood
@WeatherVane: I don't believe that's correct. Are you thinking of read()? Quoting the C standard: "The fread function returns the number of elements successfully read, which may be less than nmemb if a read error or end-of-file is encountered."Revanchism
Nope. A non-0 value returned is not EOF, it was a valid read. A 0 value returned was EOF.Knighthood
Well yes, but is not equivalent to the EOF returned by say getchar, which attempted to read past the end of the file. Perhaps I am just nitpicking.Knighthood
@WeatherVane: It pretty much is equivalent. fread() works as if by repeated calls to fgetc(). If you request fread() to read, say, 10 records and it returns 5, that means it tried and failed to read the 6th record, either because there was an error or because it reached the end of the input stream.Revanchism
For EOF or error fgetc returns EOF; fgets returns null pointer; fread returns <N.Sinotibetan
U
11

In C standard library "end of file" is not an independent self-detecting condition. "End of file" is merely a file state set by the preceding read operation. Until you perform a read operation and until that read operation bumps into the actual end of file, "eof" state is not set and feof() returns 0.

Many (most) standard I/O functions in C standard library already return some completion code that can be used to detect "end of file" condition (like fgetc() returning EOF value). This means that most of the time calling feof() is unnecessary.

In other words, if you think about "end of file" as a brick wall, in C standard library it is not sufficient to stand right in front of that wall in order to detect it. It is necessary to actually bump into that wall with your forehead in order to discover its presence.

When you open an empty file, you begin in a state "right before the wall". At this point "end of file" condition is not detected yet. You have to try reading something in order to crash into that wall and thus detect its presence.

The reasons for this design are perfectly logical. C language is designed to support various input streams and file systems, including 1) file systems that do not store file sizes at all, as well as 2) file systems that know only approximate file size (like rounded to a nearest cluster). In such file systems the end of file is usually designated by a special marker. You don't know where that marker is until you run into it while reading the file. (For the very same reason C streams do not guarantee support for positioning from SEEK_END origin in fseek function.)

As @Barmar noted in the comments, an even better example of an input stream without a pre-determined "end of file" position is standard input linked to terminal.

Upstage answered 22/3, 2016 at 20:53 Comment(2)
To add to your reasons, it might not be reading from a filesytem at all. It could be reading from a terminal, pipe, network stream, etc. These don't have file sizes.Sonometer
This is a detailed explanation, but you should expand on the distinction between input failure and end of file condition: when a read operation fails, such as fgetc() == EOF, this can mean end-of-file reached or some kind of read error. feof() can be used then to confirm if end-of-file caused the failure. This should be its only purpose.Reasonable
L
7

feof(f) will always return false right after you open the file because if gives you the value of a flag which is initialized to false and set to true only after at least one reading operation fails.

Lanthanum answered 22/3, 2016 at 20:40 Comment(0)
M
3

You could use feof like this:

fgetc(fp);
if (feof(fp))
  ...

feof checks an end-of-file indicator set after a read that attempted to read at or past the end of file. It is useful in situations where code that you don't control was reading from the file, and you want to stop the processing once the file has been exhausted.

Marylou answered 22/3, 2016 at 20:43 Comment(8)
Downvoted because newbies should not be encouraged to use feof() even with a correct explanation. What is wrong with if (fgetc(fp) == EOF)?Reasonable
A problem with this is that fgetc returning EOF indicates any error condition, but feof only checks the specific condition of end-of-file. So if there was a read error but the file is not ended then your code will go on to act on bogus data.Quote
I agree. If you say if (fgetc(fp) == EOF) and assume that it means the file was empty then you have made a big mistake because empty files might have some semantic meaning to your program. If you need to know the file is empty then you really do need to call feof() so I don't think encouraging newbies to write programs that assume a read error means that the file is empty is necessarily a good thing.Cleanlimbed
@JerryJeremiah the fact that the file was opened succesfully, but contained no data will tell you that. feof does not tell you the file is empty. It tells you you have attempted to read past the end of the file, which is what EOF tells you anyway. Please read the man page for feof, it is one of the most frequent misunderstandings.Knighthood
I understand how it works - telling me to read the man page is condescending. Opening a file means the file has been found and does NOT mean the sector containing the data has a valid checksum. Assuming that a read error means that the file is empty is asking for trouble if empty files have a semantic meaning. If knowing the file is empty or not is important then you need to actually test that specific condition. In an embedded system where the program cannot stop under any circumstances having a program work correctly under every circumstance is very important.Cleanlimbed
@Reasonable Aside from the problem of fgetc(fp) == EOF producing false positives by conflating EOF with other read errors, the answer explains what feof does in the context of the question, without necessarily endorsing its for that particular case. The last sentence is the important bit, explaining why feof is actually useful, which was not obvious to the OP.Marylou
@user4815162342: I understand your stance about read error. I knew someone would come up with this counter argument. Yet you did not write anything about this distinction in your answer. There is something fishy about fgetc() retuning EOF upon read error, the EOF value is obviously misnamed, but there is something much more fishy about feof(): the function is so commonly misused, it must have counter-intuitive semantics. I believe it is more harmful to condone the naked use of feof() than letting newbies erroneously believe that EOF means end-of-file instead of error-conditionReasonable
@Reasonable The EOF vs error argument is only part of my comment (aside from...) which I personally agree is not all that important. Consider that feof being "commonly misused" doesn't mean we can't explain to a beginner what it does. The OP explicitly asked how to use feof, and the answer explains it. Is there a problem in the answer other than your general dislike of feof?Marylou
I
0

Late answer, however to add a helpful quote from Programming in C (4th Edition) by Stephen Kochan, p. 367:

Remember, feof() tells you that an attempt has been made to read past the end of a file, which is not the same as telling you that you just read the last data item from a file. You have to read one past the last data item for feof() to return nonzero.

Italics mine.

Infrared answered 23/5, 2022 at 8:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.