-2

During read/write operations is it absolutely necessary to check feof()?

The reason I ask is because I have a program that performs read/write ONCE, here is the code below:

while (1) {

      data = read_file_data(file);
      write_file_data(data, filename);

      if (feof(file)) 
          print(read error)
}

This is just pseudocode but is it necessary to check feof() in a case like this where a read will occur once? Currently, I think it is only necessary if you will do ANOTHER read after the one above like this:

while (1) {

      data = read_file_data(file);
      write_file_data(data, filename);

      if (feof(file))       // feof error occurred oops
          print(read error)

      data = read_file_data(file); // reading after error    
}

Lastly, what can the consequences be of reading even after an EOF reached error (reading past EOF) occurs?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 2
    Check [Why is “while( !feof(file) )” always wrong?](https://stackoverflow.com/questions/5431941/why-is-while-feoffile-always-wrong) for alternatives of using `feof()`. – Eugene Sh. Aug 08 '22 at 18:48
  • You can detect the end-of-file condition a number of ways, and `feof()` is rarely the best one to use. Is your `read_data_file()` function checking for EOF, either directly by fetching a character at a time, or looking for the end-of-file return value from any other read-from-file function? – Steve Friedl Aug 08 '22 at 18:48
  • It's a bit unclear. Do you mean that `ferror(file)` is an eof check or that it is not? – klutt Aug 08 '22 at 18:48
  • @klutt sorry i meant to write feof() – programme3219873 Aug 08 '22 at 18:49
  • 2
    You should check whether each read and each write completed successfully. If it did not, you should handle the problem (perhaps by terminating the program, with a message to the user). When you do this, it is usually unnecessary to check for end-of-fie separately, except when you want to distinguish failure due to end-of-file from failure due to some I/O error. Check for end-of-file separately is otherwise useless because it **cannot** tell you whether the **next** read (or write) will succeed or fail (well, sometimes it can tell you it will fail, but it cannot guarantee success). – Eric Postpischil Aug 08 '22 at 18:49
  • @EricPostpischil if an ```EOF``` error does occur and the eof indicator is not reset will the next read fail? (assuming it is also not reset during the next read) – programme3219873 Aug 08 '22 at 18:52
  • if you ignore I/O errors and continue you invoke Undefined Behaviour. – 0___________ Aug 08 '22 at 18:52
  • @klutt really?? – programme3219873 Aug 08 '22 at 18:52
  • 2
    Also, to check whether each read or write call completed successfully, do it through the information that routine returns. Some routines return an `int` that is either a character code or an `EOF`. Otherwise return the number of items they successfully transferred. Some may put information in a place you point to. Whatever the method is, use that to detect errors, not a separate `feof` call. And build that into your subroutines—have them relay the status information to their callers, unless they fully handle it themselves. – Eric Postpischil Aug 08 '22 at 18:52
  • @programme3219873 Ignore what I said – klutt Aug 08 '22 at 18:53
  • @0___________ *if you ignore I/O errors and continue you invoke Undefined Behaviour.* Are we sure about that? – Steve Summit Aug 08 '22 at 21:59

2 Answers2

6

During read/write operations is it absolutely necessary to check feof()?

No. During normal operations, the best way of detecting EOF is to check the return value of the particular input call you're using. Input calls can always fail, so their return values should always be checked. This is especially true of scanf and fgets, which many beginning programmers (and unfortunately many beginning programming tutorials) conspicuously neglect to check.

Explicit calls to feof are rarely necessary. You might need to call feof if:

  • An input call has just returned 0 or EOF, but you'd like to know whether that was due to an actual end-of-file, or a more serious error.
  • You've used an input call such as getw() that has no way to indicate EOF or error.
  • (rare, and arguably poor form) You've made a long series of input calls in a row, and you didn't expect EOF from any of them, so you didn't feel like checking all of them explicitly, but decided to check with one catch-all call to feof() at the end.

The other thing to know is that feof() only tells you that you did hit end-of-file — that is, past tense. It does not predict the future; it does not tell you that next input call you try to make will hit EOF. It tells you that the previous call you made did hit EOF. See also Why is “while( !feof(file) )” always wrong?

See also how to detect read/write errors when using fread() and fwrite?


what can the consequences be of reading even after an EOF reached error (reading past EOF) occurs?

That's a good question. The answer is, "it depends," and since unpredictability can be a real problem, your best bet is usually not to try to read past EOF.

When I was first learning C, if you got an EOF, but tried reading some more, and if the EOF had somehow "gone away", your next read might succeed. And it could be quite common for the EOF to "go away" like that, if you were reading from the keyboard, and the user indicated EOF by typing control-D. But if they typed more input after typing control-D, you could go ahead and read it.

But that was in the old days. These days EOF is "sticky", and once the end-of-file flag has been set for a stream, I think any future attempts to read are supposed to immediately return EOF. These days, if the user hits control-D and you want to keep reading, you have to call clearerr().

I'm pretty sure everything I just said abut feof() and the per-stream EOF flag is also true of ferror() and the per-stream error flag.

In a comment, @0___________ said that "if you ignore I/O errors and continue you invoke Undefined Behaviour". I don't think this is true, but I don't have my copy of the Standard handy to check.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
4

The reason to call feof is to figure out whether the EOF return from an input function was due to some kind of actual I/O error (ferror() would return a non-zero value then but feof() wouldn't), or due to the input being exhausted (which is not an error, but a condition; feof() would return a non-zero value).

For example if your program is to consume all the input and process it, it might be crucial to be able to distinguish that you actually did read all of the input vs someone removed the USB stick from the drive when you'd read just half of the input.