Why is “while (!feof(file))” always wrong?C reading binary filesHow to read numbers from file and calculate the mean?How does C handle EOF?How do I loop through each line of a file?How to count the number of integers in a file in C?C ,fscanf(), last line is read twicefeof() on Linux return true at one line later than the ending linefeof(in) != EOF doesn't make while loop stop when at the end of file?Program Reading Last Line of File TwiceCode doesn't enter in while loop even when condition is satisfiedHow do I check whether a file exists without exceptions?How do I copy a file in Python?With arrays, why is it the case that a[5] == 5[a]?Undo working copy modifications of one file in Git?Why should text files end with a newline?How do I include a JavaScript file in another JavaScript file?Writing files in Node.jsHow to read a file line-by-line into a list?How do you append to a file in Python?Why are elementwise additions much faster in separate loops than in a combined loop?

How can an eldritch abomination hide its true form in public?

Expenditure in Poland - Forex doesn't have Zloty

How do I truncate a csv file?

When was the word "ambigu" first used with the sense of "meal with all items served at the same time"?

Why does the UK have more political parties than the US?

California: "For quality assurance, this phone call is being recorded"

What does War Machine's "Canopy! Canopy!" line mean in "Avengers: Endgame"?

What are the problems in teaching guitar via Skype?

What's the most polite way to tell a manager "shut up and let me work"?

How was Apollo supposed to rendezvous in the case of a lunar abort?

What is the most important characteristic of New Weird as a genre?

Cryptography and patents

What is the difference between a game ban and a VAC ban in Steam?

Why is Colorado so different politically from nearby states?

Accidentally cashed a check twice

Creating Fictional Slavic Place Names

How can I offer a test ride while selling a bike?

Question about IV chord in minor key

Are grass strips more dangerous than tarmac?

Do adult Russians normally hand-write Cyrillic as cursive or as block letters?

Parsing CSV with AWK to Produce HTML Output

How do I get a list of only the files (not the directories) from a package?

Explain Ant-Man's "not it" scene from Avengers: Endgame

What caused the tendency for conservatives to not support climate change regulations?



Why is “while (!feof(file))” always wrong?


C reading binary filesHow to read numbers from file and calculate the mean?How does C handle EOF?How do I loop through each line of a file?How to count the number of integers in a file in C?C ,fscanf(), last line is read twicefeof() on Linux return true at one line later than the ending linefeof(in) != EOF doesn't make while loop stop when at the end of file?Program Reading Last Line of File TwiceCode doesn't enter in while loop even when condition is satisfiedHow do I check whether a file exists without exceptions?How do I copy a file in Python?With arrays, why is it the case that a[5] == 5[a]?Undo working copy modifications of one file in Git?Why should text files end with a newline?How do I include a JavaScript file in another JavaScript file?Writing files in Node.jsHow to read a file line-by-line into a list?How do you append to a file in Python?Why are elementwise additions much faster in separate loops than in a combined loop?






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;








515















I've seen people trying to read files like this in a lot of posts lately.



Code



#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)

char * path = argc > 1 ? argv[1] : "input.txt";

FILE * fp = fopen(path, "r");
if( fp == NULL )
perror(path);
return EXIT_FAILURE;


while( !feof(fp) ) /* THIS IS WRONG */
/* Read and process data from file… */

if( fclose(fp) == 0 )
return EXIT_SUCCESS;
else
perror(path);
return EXIT_FAILURE;




What is wrong with this while( !feof(fp)) loop?










share|improve this question























  • 11





    Consider splitting your question in 2. One part as the question proper and the other part as an answer; then put that 2nd part down there ... in the answer section of SO :)

    – pmg
    Mar 25 '11 at 11:46







  • 14





    Why it's bad to use feof() to control a loop

    – Grijesh Chauhan
    Oct 17 '13 at 18:25











  • Why is iostream::eof inside a loop condition considered wrong?

    – Jonathan Wakely
    Dec 4 '14 at 9:30







  • 2





    Short answer: It tries to use a status reporting function to predict whether a future operation will succeed.

    – David Schwartz
    Mar 29 '16 at 18:26











  • How is that I never had a problem with?

    – Nguai al
    Jun 1 '18 at 22:32

















515















I've seen people trying to read files like this in a lot of posts lately.



Code



#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)

char * path = argc > 1 ? argv[1] : "input.txt";

FILE * fp = fopen(path, "r");
if( fp == NULL )
perror(path);
return EXIT_FAILURE;


while( !feof(fp) ) /* THIS IS WRONG */
/* Read and process data from file… */

if( fclose(fp) == 0 )
return EXIT_SUCCESS;
else
perror(path);
return EXIT_FAILURE;




What is wrong with this while( !feof(fp)) loop?










share|improve this question























  • 11





    Consider splitting your question in 2. One part as the question proper and the other part as an answer; then put that 2nd part down there ... in the answer section of SO :)

    – pmg
    Mar 25 '11 at 11:46







  • 14





    Why it's bad to use feof() to control a loop

    – Grijesh Chauhan
    Oct 17 '13 at 18:25











  • Why is iostream::eof inside a loop condition considered wrong?

    – Jonathan Wakely
    Dec 4 '14 at 9:30







  • 2





    Short answer: It tries to use a status reporting function to predict whether a future operation will succeed.

    – David Schwartz
    Mar 29 '16 at 18:26











  • How is that I never had a problem with?

    – Nguai al
    Jun 1 '18 at 22:32













515












515








515


256






I've seen people trying to read files like this in a lot of posts lately.



Code



#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)

char * path = argc > 1 ? argv[1] : "input.txt";

FILE * fp = fopen(path, "r");
if( fp == NULL )
perror(path);
return EXIT_FAILURE;


while( !feof(fp) ) /* THIS IS WRONG */
/* Read and process data from file… */

if( fclose(fp) == 0 )
return EXIT_SUCCESS;
else
perror(path);
return EXIT_FAILURE;




What is wrong with this while( !feof(fp)) loop?










share|improve this question
















I've seen people trying to read files like this in a lot of posts lately.



Code



#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)

char * path = argc > 1 ? argv[1] : "input.txt";

FILE * fp = fopen(path, "r");
if( fp == NULL )
perror(path);
return EXIT_FAILURE;


while( !feof(fp) ) /* THIS IS WRONG */
/* Read and process data from file… */

if( fclose(fp) == 0 )
return EXIT_SUCCESS;
else
perror(path);
return EXIT_FAILURE;




What is wrong with this while( !feof(fp)) loop?







c file while-loop feof






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Feb 13 at 14:59







William Pursell

















asked Mar 25 '11 at 11:42









William PursellWilliam Pursell

136k36213245




136k36213245












  • 11





    Consider splitting your question in 2. One part as the question proper and the other part as an answer; then put that 2nd part down there ... in the answer section of SO :)

    – pmg
    Mar 25 '11 at 11:46







  • 14





    Why it's bad to use feof() to control a loop

    – Grijesh Chauhan
    Oct 17 '13 at 18:25











  • Why is iostream::eof inside a loop condition considered wrong?

    – Jonathan Wakely
    Dec 4 '14 at 9:30







  • 2





    Short answer: It tries to use a status reporting function to predict whether a future operation will succeed.

    – David Schwartz
    Mar 29 '16 at 18:26











  • How is that I never had a problem with?

    – Nguai al
    Jun 1 '18 at 22:32












  • 11





    Consider splitting your question in 2. One part as the question proper and the other part as an answer; then put that 2nd part down there ... in the answer section of SO :)

    – pmg
    Mar 25 '11 at 11:46







  • 14





    Why it's bad to use feof() to control a loop

    – Grijesh Chauhan
    Oct 17 '13 at 18:25











  • Why is iostream::eof inside a loop condition considered wrong?

    – Jonathan Wakely
    Dec 4 '14 at 9:30







  • 2





    Short answer: It tries to use a status reporting function to predict whether a future operation will succeed.

    – David Schwartz
    Mar 29 '16 at 18:26











  • How is that I never had a problem with?

    – Nguai al
    Jun 1 '18 at 22:32







11




11





Consider splitting your question in 2. One part as the question proper and the other part as an answer; then put that 2nd part down there ... in the answer section of SO :)

– pmg
Mar 25 '11 at 11:46






Consider splitting your question in 2. One part as the question proper and the other part as an answer; then put that 2nd part down there ... in the answer section of SO :)

– pmg
Mar 25 '11 at 11:46





14




14





Why it's bad to use feof() to control a loop

– Grijesh Chauhan
Oct 17 '13 at 18:25





Why it's bad to use feof() to control a loop

– Grijesh Chauhan
Oct 17 '13 at 18:25













Why is iostream::eof inside a loop condition considered wrong?

– Jonathan Wakely
Dec 4 '14 at 9:30






Why is iostream::eof inside a loop condition considered wrong?

– Jonathan Wakely
Dec 4 '14 at 9:30





2




2





Short answer: It tries to use a status reporting function to predict whether a future operation will succeed.

– David Schwartz
Mar 29 '16 at 18:26





Short answer: It tries to use a status reporting function to predict whether a future operation will succeed.

– David Schwartz
Mar 29 '16 at 18:26













How is that I never had a problem with?

– Nguai al
Jun 1 '18 at 22:32





How is that I never had a problem with?

– Nguai al
Jun 1 '18 at 22:32












5 Answers
5






active

oldest

votes


















409














I'd like to provide an abstract, high-level perspective.



Concurrency and simultaneity



I/O operations interact with the environment. The environment is not part of your program, and not under your control. The environment truly exists "concurrently" with your program. As with all things concurrent, questions about the "current state" don't make sense: There is no concept of "simultaneity" across concurrent events. Many properties of state simply don't exist concurrently.



Let me make this more precise: Suppose you want to ask, "do you have more data". You could ask this of a concurrent container, or of your I/O system. But the answer is generally unactionable, and thus meaningless. So what if the container says "yes" – by the time you try reading, it may no longer have data. Similarly, if the answer is "no", by the time you try reading, data may have arrived. The conclusion is that there simply is no property like "I have data", since you cannot act meaningfully in response to any possible answer. (The situation is slightly better with buffered input, where you might conceivably get a "yes, I have data" that constitutes some kind of guarantee, but you would still have to be able to deal with the opposite case. And with output the situation is certainly just as bad as I described: you never know if that disk or that network buffer is full.)



So we conclude that it is impossible, and in fact unreasonable, to ask an I/O system whether it will be able to perform an I/O operation. The only possible way we can interact with it (just as with a concurrent container) is to attempt the operation and check whether it succeeded or failed. At that moment where you interact with the environment, then and only then can you know whether the interaction was actually possible, and at that point you must commit to performing the interaction. (This is a "synchronisation point", if you will.)



EOF



Now we get to EOF. EOF is the response you get from an attempted I/O operation. It means that you were trying to read or write something, but when doing so you failed to read or write any data, and instead the end of the input or output was encountered. This is true for essentially all the I/O APIs, whether it be the C standard library, C++ iostreams, or other libraries. As long as the I/O operations succeed, you simply cannot know whether further, future operations will succeed. You must always first try the operation and then respond to success or failure.



Examples



In each of the examples, note carefully that we first attempt the I/O operation and then consume the result if it is valid. Note further that we always must use the result of the I/O operation, though the result takes different shapes and forms in each example.




  • C stdio, read from a file:



    for (;;) 
    size_t n = fread(buf, 1, bufsize, infile);
    consume(buf, n);
    if (n < bufsize) break;



    The result we must use is n, the number of elements that were read (which may be as little as zero).




  • C stdio, scanf:



    for (int a, b, c; scanf("%d %d %d", &a, &b, &c) == 3; ) 
    consume(a, b, c);



    The result we must use is the return value of scanf, the number of elements converted.




  • C++, iostreams formatted extraction:



    for (int n; std::cin >> n; ) 
    consume(n);



    The result we must use is std::cin itself, which can be evaluated in a boolean context and tells us whether the stream is still in the good() state.




  • C++, iostreams getline:



    for (std::string line; std::getline(std::cin, line); ) 
    consume(line);



    The result we must use is again std::cin, just as before.




  • POSIX, write(2) to flush a buffer:



    char const * p = buf;
    ssize_t n = bufsize;
    for (ssize_t k = bufsize; (k = write(fd, p, n)) > 0; p += k, n -= k)
    if (n != 0) /* error, failed to write complete buffer */


    The result we use here is k, the number of bytes written. The point here is that we can only know how many bytes were written after the write operation.




  • POSIX getline()



    char *buffer = NULL;
    size_t bufsiz = 0;
    ssize_t nbytes;
    while ((nbytes = getline(&buffer, &bufsiz, fp)) != -1)

    /* Use nbytes of data in buffer */

    free(buffer);


    The result we must use is nbytes, the number of bytes up to and including the newline (or EOF if the file did not end with a newline).



    Note that the function explicitly returns -1 (and not EOF!) when an error occurs or it reaches EOF.



You may notice that we very rarely spell out the actual word "EOF". We usually detect the error condition in some other way that is more immediately interesting to us (e.g. failure to perform as much I/O as we had desired). In every example there is some API feature that could tell us explicitly that the EOF state has been encountered, but this is in fact not a terribly useful piece of information. It is much more of a detail than we often care about. What matters is whether the I/O succeeded, more-so than how it failed.




  • A final example that actually queries the EOF state: Suppose you have a string and want to test that it represents an integer in its entirety, with no extra bits at the end except whitespace. Using C++ iostreams, it goes like this:



    std::string input = " 123 "; // example

    std::istringstream iss(input);
    int value;
    if (iss >> value >> std::ws && iss.get() == EOF)
    consume(value);
    else
    // error, "input" is not parsable as an integer



    We use two results here. The first is iss, the stream object itself, to check that the formatted extraction to value succeeded. But then, after also consuming whitespace, we perform another I/O/ operation, iss.get(), and expect it to fail as EOF, which is the case if the entire string has already been consumed by the formatted extraction.



    In the C standard library you can achieve something similar with the strto*l functions by checking that the end pointer has reached the end of the input string.



The answer



while(!eof) is wrong because it tests for something that is irrelevant and fails to test for something that you need to know. The result is that you are erroneously executing code that assumes that it is accessing data that was read successfully, when in fact this never happened.






share|improve this answer




















  • 26





    @CiaPan: I don't think that's true. Both C99 and C11 allow this.

    – Kerrek SB
    Jan 29 '15 at 12:10






  • 9





    But ANSI C does not.

    – CiaPan
    Jan 29 '15 at 12:25






  • 1





    @JonathanMee: It's bad for all the reasons I mention: you cannot look into the future. You cannot tell what will happen in the future.

    – Kerrek SB
    Feb 3 '15 at 20:52






  • 2





    @JonathanMee: Yes, that would be appropriate, though usually you can combine this check into the operation (since most iostreams operations return the stream object, which itself has a boolean conversion), and that way you make it obvious that you're not ignoring the return value.

    – Kerrek SB
    Feb 3 '15 at 21:02






  • 1





    The std::cin and scanf examples happily treat bad input (something worth raising an error) as EOF (which just means leave the loop).

    – ex-bart
    Jul 31 '15 at 23:41


















218














It's wrong because (in the absence of a read error) it enters the loop one more time than the author expects. If there is a read error, the loop never terminates.



Consider the following code:



/* WARNING: demonstration of bad coding technique!! */

#include <stdio.h>
#include <stdlib.h>

FILE *Fopen(const char *path, const char *mode);

int main(int argc, char **argv)

FILE *in;
unsigned count;

in = argc > 1 ? Fopen(argv[1], "r") : stdin;
count = 0;

/* WARNING: this is a bug */
while (!feof(in)) /* This is WRONG! */
fgetc(in);
count++;

printf("Number of characters read: %un", count);
return EXIT_SUCCESS;


FILE * Fopen(const char *path, const char *mode)

FILE *f = fopen(path, mode);
if (f == NULL)
perror(path);
exit(EXIT_FAILURE);

return f;



This program will consistently print one greater than the number of characters in the input stream (assuming no read errors). Consider the case where the input stream is empty:



$ ./a.out < /dev/null
Number of characters read: 1


In this case, feof() is called before any data has been read, so it returns false. The loop is entered, fgetc() is called (and returns EOF), and count is incremented. Then feof() is called and returns true, causing the loop to abort.



This happens in all such cases. feof() does not return true until after a read on the stream encounters the end of file. The purpose of feof() is NOT to check if the next read will reach the end of file. The purpose of feof() is to distinguish between a read error and having reached the end of the file. If fread() returns 0, you must use feof/ferror to decide. Similarly if fgetc returns EOF. feof() is only useful after fread has returned zero or fgetc has returned EOF. Before that happens, feof() will always return 0.



It is always necessary to check the return value of a read (either an fread(), or an fscanf(), or an fgetc()) before calling feof().



Even worse, consider the case where a read error occurs. In that case, fgetc() returns EOF, feof() returns false, and the loop never terminates. In all cases where while(!feof(p)) is used, there must be at least a check inside the loop for ferror(), or at the very least the while condition should be replaced with while(!feof(p) && !ferror(p)) or there is a very real possibility of an infinite loop, probably spewing all sorts of garbage as invalid data is being processed.



So, in summary, although I cannot state with certainty that there is never a situation in which it may be semantically correct to write "while(!feof(f))" (although there must be another check inside the loop with a break to avoid a infinite loop on a read error), it is the case that it is almost certainly always wrong. And even if a case ever arose where it would be correct, it is so idiomatically wrong that it would not be the right way to write the code. Anyone seeing that code should immediately hesitate and say, "that's a bug". And possibly slap the author (unless the author is your boss in which case discretion is advised.)






share|improve this answer




















  • 16





    Mutlitple downvotes today: any explanation? If you disagree, please explain your reasons.

    – William Pursell
    Jun 5 '12 at 15:29






  • 6





    Sure it's wrong -- but aside from that it isn't "gratingly ugly".

    – nobar
    Jul 7 '13 at 0:53






  • 80





    You should add an example of correct code, as I imagine lots of people will come here looking for a quick fix.

    – jleahy
    Jul 12 '13 at 16:27






  • 2





    @Thomas: I'm not a C++ expert, but I believe file.eof() returns effectively the same result as feof(file) || ferror(file), so it is very different. But this question is not intended to be applicable to C++.

    – William Pursell
    Aug 26 '14 at 23:36






  • 6





    @m-ric that's not right either, because you'll still try to process a read that failed.

    – Mark Ransom
    Apr 9 '15 at 18:25


















60














No it's not always wrong. If your loop condition is "while we haven't tried to read past end of file" then you use while (!feof(f)). This is however not a common loop condition - usually you want to test for something else (such as "can I read more"). while (!feof(f)) isn't wrong, it's just used wrong.






share|improve this answer


















  • 1





    I wonder ... f = fopen("A:\bigfile"); while (!feof(f)) /* remove diskette */ or (going to test this) f = fopen(NETWORK_FILE); while (!feof(f)) /* unplug network cable */

    – pmg
    Mar 25 '11 at 11:53







  • 1





    @pmg: As said, "not a common loop condition" hehe. I can't really think of any case I've needed it, usually I'm interested in "could I read what I wanted" with all that implies of error handling

    – Erik
    Mar 25 '11 at 11:56











  • @pmg: As said, you rarely want while(!eof(f))

    – Erik
    Mar 25 '11 at 12:41






  • 7





    More accurately, the condition is "while we haven't tried to read past the end of the file and there was no read error" feof is not about detecting end of file; it is about determining whether a read was short because of an error or because the input is exhausted.

    – William Pursell
    Jul 3 '13 at 15:18


















29














feof() indicates if one has tried to read past the end of file. That means it has little predictive effect: if it is true, you are sure that the next input operation will fail (you aren't sure the previous one failed BTW), but if it is false, you aren't sure the next input operation will succeed. More over, input operations may fail for other reasons than the end of file (a format error for formatted input, a pure IO failure -- disk failure, network timeout -- for all input kinds), so even if you could be predictive about the end of file (and anybody who has tried to implement Ada one, which is predictive, will tell you it can complex if you need to skip spaces, and that it has undesirable effects on interactive devices -- sometimes forcing the input of the next line before starting the handling of the previous one), you would have to be able to handle a failure.



So the correct idiom in C is to loop with the IO operation success as loop condition, and then test the cause of the failure. For instance:



while (fgets(line, sizeof(line), file)) 
/* note that fgets don't strip the terminating n, checking its
presence allow to handle lines longer that sizeof(line), not showed here */
...

if (ferror(file))
/* IO failure */
else if (feof(file))
/* format error (not possible with fgets, but would be with fscanf) or end of file */
else
/* format error (not possible with fgets, but would be with fscanf) */






share|improve this answer


















  • 2





    Getting to the end of a file is not an error, so I question the phrasing "input operations may fail for other reasons than the end of file".

    – William Pursell
    Sep 29 '12 at 12:59











  • @WilliamPursell, reaching the eof isn't necessarily an error, but being unable to do an input operation because of eof is one. And it is impossible in C to detect reliably the eof without having made an input operation fails.

    – AProgrammer
    Sep 29 '12 at 15:12











  • Agree last else not possible with sizeof(line) >= 2 and fgets(line, sizeof(line), file) but possible with pathological size <= 0 and fgets(line, size, file). Maybe even possible with sizeof(line) == 1.

    – chux
    Mar 26 '15 at 21:21











  • All that "predictive value" talk... I never thought about it that way. In my world, feof(f) does not PREDICT anything. It states that a PREVIOUS operation has hit the end of the file. Nothing more, nothing less. And if there was no previous operation (just opened it), it does not report end of file even if the file was empty to start with. So, apart of the concurrency explanation in another answer above, I do not think there is any reason not to loop on feof(f).

    – BitTickler
    Sep 24 '17 at 20:36











  • @AProgrammer: A "read up to N bytes" request that yields zero, whether because of a "permanent" EOF or because no more data is available yet, is not an error. While feof() may not reliably predict that future requests will yield data, it may reliably indicate that future requests won't. Perhaps there should be a status function that would indicate "It is plausible that future read requests will succeed", with semantics that after reading to the end of an ordinary file, a quality implementation should say future reads are unlikely to succeed absent some reason to believe they might.

    – supercat
    Feb 3 at 15:49



















10














Great answer, I just noticed the same thing because I was trying to do a loop like that. So, it's wrong in that scenario, but if you want to have a loop that gracefully ends at the EOF, this is a nice way to do it:



#include <stdio.h>
#include <sys/stat.h>
int main(int argc, char *argv[])

struct stat buf;
FILE *fp = fopen(argv[0], "r");
stat(filename, &buf);
while (ftello(fp) != buf.st_size)
(void)fgetc(fp);

// all done, read all the bytes






share|improve this answer

























  • This is an interesting approach, but does not work on a fifo. It doesn't seem to offer any benefit over while( fgetc(fp) != EOF )

    – William Pursell
    Jun 2 '13 at 11:34






  • 1





    True, but sometimes you don't use fgetc() to read files. For example, reading structured records, I have a read function (in this example where there's a fgetc) which detects errors and reads exactly one record, but it doesn't know how many records are in the file. Yes, it's wrong for fifos, or any other file that might change while you have it open.

    – tesch1
    Jun 3 '13 at 2:46












  • while( read_structured_record( fp ) == 1 ) { ... would be an idiomatic way to write that (assuming read_structured_record returns the number of records read).

    – William Pursell
    Jun 3 '13 at 13:38







  • 1





    File I/O errors may happen anytime, thus by not checking the result of fgetc(fp), one may miss that and not read all the bytes.

    – chux
    Sep 13 '13 at 17:47






  • 1





    Files can grow while you are reading them; they can also shrink. The size given by the one-time stat() operation is not reliable over the long term.

    – Jonathan Leffler
    Mar 26 '15 at 17:55

















5 Answers
5






active

oldest

votes








5 Answers
5






active

oldest

votes









active

oldest

votes






active

oldest

votes









409














I'd like to provide an abstract, high-level perspective.



Concurrency and simultaneity



I/O operations interact with the environment. The environment is not part of your program, and not under your control. The environment truly exists "concurrently" with your program. As with all things concurrent, questions about the "current state" don't make sense: There is no concept of "simultaneity" across concurrent events. Many properties of state simply don't exist concurrently.



Let me make this more precise: Suppose you want to ask, "do you have more data". You could ask this of a concurrent container, or of your I/O system. But the answer is generally unactionable, and thus meaningless. So what if the container says "yes" – by the time you try reading, it may no longer have data. Similarly, if the answer is "no", by the time you try reading, data may have arrived. The conclusion is that there simply is no property like "I have data", since you cannot act meaningfully in response to any possible answer. (The situation is slightly better with buffered input, where you might conceivably get a "yes, I have data" that constitutes some kind of guarantee, but you would still have to be able to deal with the opposite case. And with output the situation is certainly just as bad as I described: you never know if that disk or that network buffer is full.)



So we conclude that it is impossible, and in fact unreasonable, to ask an I/O system whether it will be able to perform an I/O operation. The only possible way we can interact with it (just as with a concurrent container) is to attempt the operation and check whether it succeeded or failed. At that moment where you interact with the environment, then and only then can you know whether the interaction was actually possible, and at that point you must commit to performing the interaction. (This is a "synchronisation point", if you will.)



EOF



Now we get to EOF. EOF is the response you get from an attempted I/O operation. It means that you were trying to read or write something, but when doing so you failed to read or write any data, and instead the end of the input or output was encountered. This is true for essentially all the I/O APIs, whether it be the C standard library, C++ iostreams, or other libraries. As long as the I/O operations succeed, you simply cannot know whether further, future operations will succeed. You must always first try the operation and then respond to success or failure.



Examples



In each of the examples, note carefully that we first attempt the I/O operation and then consume the result if it is valid. Note further that we always must use the result of the I/O operation, though the result takes different shapes and forms in each example.




  • C stdio, read from a file:



    for (;;) 
    size_t n = fread(buf, 1, bufsize, infile);
    consume(buf, n);
    if (n < bufsize) break;



    The result we must use is n, the number of elements that were read (which may be as little as zero).




  • C stdio, scanf:



    for (int a, b, c; scanf("%d %d %d", &a, &b, &c) == 3; ) 
    consume(a, b, c);



    The result we must use is the return value of scanf, the number of elements converted.




  • C++, iostreams formatted extraction:



    for (int n; std::cin >> n; ) 
    consume(n);



    The result we must use is std::cin itself, which can be evaluated in a boolean context and tells us whether the stream is still in the good() state.




  • C++, iostreams getline:



    for (std::string line; std::getline(std::cin, line); ) 
    consume(line);



    The result we must use is again std::cin, just as before.




  • POSIX, write(2) to flush a buffer:



    char const * p = buf;
    ssize_t n = bufsize;
    for (ssize_t k = bufsize; (k = write(fd, p, n)) > 0; p += k, n -= k)
    if (n != 0) /* error, failed to write complete buffer */


    The result we use here is k, the number of bytes written. The point here is that we can only know how many bytes were written after the write operation.




  • POSIX getline()



    char *buffer = NULL;
    size_t bufsiz = 0;
    ssize_t nbytes;
    while ((nbytes = getline(&buffer, &bufsiz, fp)) != -1)

    /* Use nbytes of data in buffer */

    free(buffer);


    The result we must use is nbytes, the number of bytes up to and including the newline (or EOF if the file did not end with a newline).



    Note that the function explicitly returns -1 (and not EOF!) when an error occurs or it reaches EOF.



You may notice that we very rarely spell out the actual word "EOF". We usually detect the error condition in some other way that is more immediately interesting to us (e.g. failure to perform as much I/O as we had desired). In every example there is some API feature that could tell us explicitly that the EOF state has been encountered, but this is in fact not a terribly useful piece of information. It is much more of a detail than we often care about. What matters is whether the I/O succeeded, more-so than how it failed.




  • A final example that actually queries the EOF state: Suppose you have a string and want to test that it represents an integer in its entirety, with no extra bits at the end except whitespace. Using C++ iostreams, it goes like this:



    std::string input = " 123 "; // example

    std::istringstream iss(input);
    int value;
    if (iss >> value >> std::ws && iss.get() == EOF)
    consume(value);
    else
    // error, "input" is not parsable as an integer



    We use two results here. The first is iss, the stream object itself, to check that the formatted extraction to value succeeded. But then, after also consuming whitespace, we perform another I/O/ operation, iss.get(), and expect it to fail as EOF, which is the case if the entire string has already been consumed by the formatted extraction.



    In the C standard library you can achieve something similar with the strto*l functions by checking that the end pointer has reached the end of the input string.



The answer



while(!eof) is wrong because it tests for something that is irrelevant and fails to test for something that you need to know. The result is that you are erroneously executing code that assumes that it is accessing data that was read successfully, when in fact this never happened.






share|improve this answer




















  • 26





    @CiaPan: I don't think that's true. Both C99 and C11 allow this.

    – Kerrek SB
    Jan 29 '15 at 12:10






  • 9





    But ANSI C does not.

    – CiaPan
    Jan 29 '15 at 12:25






  • 1





    @JonathanMee: It's bad for all the reasons I mention: you cannot look into the future. You cannot tell what will happen in the future.

    – Kerrek SB
    Feb 3 '15 at 20:52






  • 2





    @JonathanMee: Yes, that would be appropriate, though usually you can combine this check into the operation (since most iostreams operations return the stream object, which itself has a boolean conversion), and that way you make it obvious that you're not ignoring the return value.

    – Kerrek SB
    Feb 3 '15 at 21:02






  • 1





    The std::cin and scanf examples happily treat bad input (something worth raising an error) as EOF (which just means leave the loop).

    – ex-bart
    Jul 31 '15 at 23:41















409














I'd like to provide an abstract, high-level perspective.



Concurrency and simultaneity



I/O operations interact with the environment. The environment is not part of your program, and not under your control. The environment truly exists "concurrently" with your program. As with all things concurrent, questions about the "current state" don't make sense: There is no concept of "simultaneity" across concurrent events. Many properties of state simply don't exist concurrently.



Let me make this more precise: Suppose you want to ask, "do you have more data". You could ask this of a concurrent container, or of your I/O system. But the answer is generally unactionable, and thus meaningless. So what if the container says "yes" – by the time you try reading, it may no longer have data. Similarly, if the answer is "no", by the time you try reading, data may have arrived. The conclusion is that there simply is no property like "I have data", since you cannot act meaningfully in response to any possible answer. (The situation is slightly better with buffered input, where you might conceivably get a "yes, I have data" that constitutes some kind of guarantee, but you would still have to be able to deal with the opposite case. And with output the situation is certainly just as bad as I described: you never know if that disk or that network buffer is full.)



So we conclude that it is impossible, and in fact unreasonable, to ask an I/O system whether it will be able to perform an I/O operation. The only possible way we can interact with it (just as with a concurrent container) is to attempt the operation and check whether it succeeded or failed. At that moment where you interact with the environment, then and only then can you know whether the interaction was actually possible, and at that point you must commit to performing the interaction. (This is a "synchronisation point", if you will.)



EOF



Now we get to EOF. EOF is the response you get from an attempted I/O operation. It means that you were trying to read or write something, but when doing so you failed to read or write any data, and instead the end of the input or output was encountered. This is true for essentially all the I/O APIs, whether it be the C standard library, C++ iostreams, or other libraries. As long as the I/O operations succeed, you simply cannot know whether further, future operations will succeed. You must always first try the operation and then respond to success or failure.



Examples



In each of the examples, note carefully that we first attempt the I/O operation and then consume the result if it is valid. Note further that we always must use the result of the I/O operation, though the result takes different shapes and forms in each example.




  • C stdio, read from a file:



    for (;;) 
    size_t n = fread(buf, 1, bufsize, infile);
    consume(buf, n);
    if (n < bufsize) break;



    The result we must use is n, the number of elements that were read (which may be as little as zero).




  • C stdio, scanf:



    for (int a, b, c; scanf("%d %d %d", &a, &b, &c) == 3; ) 
    consume(a, b, c);



    The result we must use is the return value of scanf, the number of elements converted.




  • C++, iostreams formatted extraction:



    for (int n; std::cin >> n; ) 
    consume(n);



    The result we must use is std::cin itself, which can be evaluated in a boolean context and tells us whether the stream is still in the good() state.




  • C++, iostreams getline:



    for (std::string line; std::getline(std::cin, line); ) 
    consume(line);



    The result we must use is again std::cin, just as before.




  • POSIX, write(2) to flush a buffer:



    char const * p = buf;
    ssize_t n = bufsize;
    for (ssize_t k = bufsize; (k = write(fd, p, n)) > 0; p += k, n -= k)
    if (n != 0) /* error, failed to write complete buffer */


    The result we use here is k, the number of bytes written. The point here is that we can only know how many bytes were written after the write operation.




  • POSIX getline()



    char *buffer = NULL;
    size_t bufsiz = 0;
    ssize_t nbytes;
    while ((nbytes = getline(&buffer, &bufsiz, fp)) != -1)

    /* Use nbytes of data in buffer */

    free(buffer);


    The result we must use is nbytes, the number of bytes up to and including the newline (or EOF if the file did not end with a newline).



    Note that the function explicitly returns -1 (and not EOF!) when an error occurs or it reaches EOF.



You may notice that we very rarely spell out the actual word "EOF". We usually detect the error condition in some other way that is more immediately interesting to us (e.g. failure to perform as much I/O as we had desired). In every example there is some API feature that could tell us explicitly that the EOF state has been encountered, but this is in fact not a terribly useful piece of information. It is much more of a detail than we often care about. What matters is whether the I/O succeeded, more-so than how it failed.




  • A final example that actually queries the EOF state: Suppose you have a string and want to test that it represents an integer in its entirety, with no extra bits at the end except whitespace. Using C++ iostreams, it goes like this:



    std::string input = " 123 "; // example

    std::istringstream iss(input);
    int value;
    if (iss >> value >> std::ws && iss.get() == EOF)
    consume(value);
    else
    // error, "input" is not parsable as an integer



    We use two results here. The first is iss, the stream object itself, to check that the formatted extraction to value succeeded. But then, after also consuming whitespace, we perform another I/O/ operation, iss.get(), and expect it to fail as EOF, which is the case if the entire string has already been consumed by the formatted extraction.



    In the C standard library you can achieve something similar with the strto*l functions by checking that the end pointer has reached the end of the input string.



The answer



while(!eof) is wrong because it tests for something that is irrelevant and fails to test for something that you need to know. The result is that you are erroneously executing code that assumes that it is accessing data that was read successfully, when in fact this never happened.






share|improve this answer




















  • 26





    @CiaPan: I don't think that's true. Both C99 and C11 allow this.

    – Kerrek SB
    Jan 29 '15 at 12:10






  • 9





    But ANSI C does not.

    – CiaPan
    Jan 29 '15 at 12:25






  • 1





    @JonathanMee: It's bad for all the reasons I mention: you cannot look into the future. You cannot tell what will happen in the future.

    – Kerrek SB
    Feb 3 '15 at 20:52






  • 2





    @JonathanMee: Yes, that would be appropriate, though usually you can combine this check into the operation (since most iostreams operations return the stream object, which itself has a boolean conversion), and that way you make it obvious that you're not ignoring the return value.

    – Kerrek SB
    Feb 3 '15 at 21:02






  • 1





    The std::cin and scanf examples happily treat bad input (something worth raising an error) as EOF (which just means leave the loop).

    – ex-bart
    Jul 31 '15 at 23:41













409












409








409







I'd like to provide an abstract, high-level perspective.



Concurrency and simultaneity



I/O operations interact with the environment. The environment is not part of your program, and not under your control. The environment truly exists "concurrently" with your program. As with all things concurrent, questions about the "current state" don't make sense: There is no concept of "simultaneity" across concurrent events. Many properties of state simply don't exist concurrently.



Let me make this more precise: Suppose you want to ask, "do you have more data". You could ask this of a concurrent container, or of your I/O system. But the answer is generally unactionable, and thus meaningless. So what if the container says "yes" – by the time you try reading, it may no longer have data. Similarly, if the answer is "no", by the time you try reading, data may have arrived. The conclusion is that there simply is no property like "I have data", since you cannot act meaningfully in response to any possible answer. (The situation is slightly better with buffered input, where you might conceivably get a "yes, I have data" that constitutes some kind of guarantee, but you would still have to be able to deal with the opposite case. And with output the situation is certainly just as bad as I described: you never know if that disk or that network buffer is full.)



So we conclude that it is impossible, and in fact unreasonable, to ask an I/O system whether it will be able to perform an I/O operation. The only possible way we can interact with it (just as with a concurrent container) is to attempt the operation and check whether it succeeded or failed. At that moment where you interact with the environment, then and only then can you know whether the interaction was actually possible, and at that point you must commit to performing the interaction. (This is a "synchronisation point", if you will.)



EOF



Now we get to EOF. EOF is the response you get from an attempted I/O operation. It means that you were trying to read or write something, but when doing so you failed to read or write any data, and instead the end of the input or output was encountered. This is true for essentially all the I/O APIs, whether it be the C standard library, C++ iostreams, or other libraries. As long as the I/O operations succeed, you simply cannot know whether further, future operations will succeed. You must always first try the operation and then respond to success or failure.



Examples



In each of the examples, note carefully that we first attempt the I/O operation and then consume the result if it is valid. Note further that we always must use the result of the I/O operation, though the result takes different shapes and forms in each example.




  • C stdio, read from a file:



    for (;;) 
    size_t n = fread(buf, 1, bufsize, infile);
    consume(buf, n);
    if (n < bufsize) break;



    The result we must use is n, the number of elements that were read (which may be as little as zero).




  • C stdio, scanf:



    for (int a, b, c; scanf("%d %d %d", &a, &b, &c) == 3; ) 
    consume(a, b, c);



    The result we must use is the return value of scanf, the number of elements converted.




  • C++, iostreams formatted extraction:



    for (int n; std::cin >> n; ) 
    consume(n);



    The result we must use is std::cin itself, which can be evaluated in a boolean context and tells us whether the stream is still in the good() state.




  • C++, iostreams getline:



    for (std::string line; std::getline(std::cin, line); ) 
    consume(line);



    The result we must use is again std::cin, just as before.




  • POSIX, write(2) to flush a buffer:



    char const * p = buf;
    ssize_t n = bufsize;
    for (ssize_t k = bufsize; (k = write(fd, p, n)) > 0; p += k, n -= k)
    if (n != 0) /* error, failed to write complete buffer */


    The result we use here is k, the number of bytes written. The point here is that we can only know how many bytes were written after the write operation.




  • POSIX getline()



    char *buffer = NULL;
    size_t bufsiz = 0;
    ssize_t nbytes;
    while ((nbytes = getline(&buffer, &bufsiz, fp)) != -1)

    /* Use nbytes of data in buffer */

    free(buffer);


    The result we must use is nbytes, the number of bytes up to and including the newline (or EOF if the file did not end with a newline).



    Note that the function explicitly returns -1 (and not EOF!) when an error occurs or it reaches EOF.



You may notice that we very rarely spell out the actual word "EOF". We usually detect the error condition in some other way that is more immediately interesting to us (e.g. failure to perform as much I/O as we had desired). In every example there is some API feature that could tell us explicitly that the EOF state has been encountered, but this is in fact not a terribly useful piece of information. It is much more of a detail than we often care about. What matters is whether the I/O succeeded, more-so than how it failed.




  • A final example that actually queries the EOF state: Suppose you have a string and want to test that it represents an integer in its entirety, with no extra bits at the end except whitespace. Using C++ iostreams, it goes like this:



    std::string input = " 123 "; // example

    std::istringstream iss(input);
    int value;
    if (iss >> value >> std::ws && iss.get() == EOF)
    consume(value);
    else
    // error, "input" is not parsable as an integer



    We use two results here. The first is iss, the stream object itself, to check that the formatted extraction to value succeeded. But then, after also consuming whitespace, we perform another I/O/ operation, iss.get(), and expect it to fail as EOF, which is the case if the entire string has already been consumed by the formatted extraction.



    In the C standard library you can achieve something similar with the strto*l functions by checking that the end pointer has reached the end of the input string.



The answer



while(!eof) is wrong because it tests for something that is irrelevant and fails to test for something that you need to know. The result is that you are erroneously executing code that assumes that it is accessing data that was read successfully, when in fact this never happened.






share|improve this answer















I'd like to provide an abstract, high-level perspective.



Concurrency and simultaneity



I/O operations interact with the environment. The environment is not part of your program, and not under your control. The environment truly exists "concurrently" with your program. As with all things concurrent, questions about the "current state" don't make sense: There is no concept of "simultaneity" across concurrent events. Many properties of state simply don't exist concurrently.



Let me make this more precise: Suppose you want to ask, "do you have more data". You could ask this of a concurrent container, or of your I/O system. But the answer is generally unactionable, and thus meaningless. So what if the container says "yes" – by the time you try reading, it may no longer have data. Similarly, if the answer is "no", by the time you try reading, data may have arrived. The conclusion is that there simply is no property like "I have data", since you cannot act meaningfully in response to any possible answer. (The situation is slightly better with buffered input, where you might conceivably get a "yes, I have data" that constitutes some kind of guarantee, but you would still have to be able to deal with the opposite case. And with output the situation is certainly just as bad as I described: you never know if that disk or that network buffer is full.)



So we conclude that it is impossible, and in fact unreasonable, to ask an I/O system whether it will be able to perform an I/O operation. The only possible way we can interact with it (just as with a concurrent container) is to attempt the operation and check whether it succeeded or failed. At that moment where you interact with the environment, then and only then can you know whether the interaction was actually possible, and at that point you must commit to performing the interaction. (This is a "synchronisation point", if you will.)



EOF



Now we get to EOF. EOF is the response you get from an attempted I/O operation. It means that you were trying to read or write something, but when doing so you failed to read or write any data, and instead the end of the input or output was encountered. This is true for essentially all the I/O APIs, whether it be the C standard library, C++ iostreams, or other libraries. As long as the I/O operations succeed, you simply cannot know whether further, future operations will succeed. You must always first try the operation and then respond to success or failure.



Examples



In each of the examples, note carefully that we first attempt the I/O operation and then consume the result if it is valid. Note further that we always must use the result of the I/O operation, though the result takes different shapes and forms in each example.




  • C stdio, read from a file:



    for (;;) 
    size_t n = fread(buf, 1, bufsize, infile);
    consume(buf, n);
    if (n < bufsize) break;



    The result we must use is n, the number of elements that were read (which may be as little as zero).




  • C stdio, scanf:



    for (int a, b, c; scanf("%d %d %d", &a, &b, &c) == 3; ) 
    consume(a, b, c);



    The result we must use is the return value of scanf, the number of elements converted.




  • C++, iostreams formatted extraction:



    for (int n; std::cin >> n; ) 
    consume(n);



    The result we must use is std::cin itself, which can be evaluated in a boolean context and tells us whether the stream is still in the good() state.




  • C++, iostreams getline:



    for (std::string line; std::getline(std::cin, line); ) 
    consume(line);



    The result we must use is again std::cin, just as before.




  • POSIX, write(2) to flush a buffer:



    char const * p = buf;
    ssize_t n = bufsize;
    for (ssize_t k = bufsize; (k = write(fd, p, n)) > 0; p += k, n -= k)
    if (n != 0) /* error, failed to write complete buffer */


    The result we use here is k, the number of bytes written. The point here is that we can only know how many bytes were written after the write operation.




  • POSIX getline()



    char *buffer = NULL;
    size_t bufsiz = 0;
    ssize_t nbytes;
    while ((nbytes = getline(&buffer, &bufsiz, fp)) != -1)

    /* Use nbytes of data in buffer */

    free(buffer);


    The result we must use is nbytes, the number of bytes up to and including the newline (or EOF if the file did not end with a newline).



    Note that the function explicitly returns -1 (and not EOF!) when an error occurs or it reaches EOF.



You may notice that we very rarely spell out the actual word "EOF". We usually detect the error condition in some other way that is more immediately interesting to us (e.g. failure to perform as much I/O as we had desired). In every example there is some API feature that could tell us explicitly that the EOF state has been encountered, but this is in fact not a terribly useful piece of information. It is much more of a detail than we often care about. What matters is whether the I/O succeeded, more-so than how it failed.




  • A final example that actually queries the EOF state: Suppose you have a string and want to test that it represents an integer in its entirety, with no extra bits at the end except whitespace. Using C++ iostreams, it goes like this:



    std::string input = " 123 "; // example

    std::istringstream iss(input);
    int value;
    if (iss >> value >> std::ws && iss.get() == EOF)
    consume(value);
    else
    // error, "input" is not parsable as an integer



    We use two results here. The first is iss, the stream object itself, to check that the formatted extraction to value succeeded. But then, after also consuming whitespace, we perform another I/O/ operation, iss.get(), and expect it to fail as EOF, which is the case if the entire string has already been consumed by the formatted extraction.



    In the C standard library you can achieve something similar with the strto*l functions by checking that the end pointer has reached the end of the input string.



The answer



while(!eof) is wrong because it tests for something that is irrelevant and fails to test for something that you need to know. The result is that you are erroneously executing code that assumes that it is accessing data that was read successfully, when in fact this never happened.







share|improve this answer














share|improve this answer



share|improve this answer








edited May 24 '17 at 15:58

























answered Oct 24 '14 at 22:28









Kerrek SBKerrek SB

374k61707945




374k61707945







  • 26





    @CiaPan: I don't think that's true. Both C99 and C11 allow this.

    – Kerrek SB
    Jan 29 '15 at 12:10






  • 9





    But ANSI C does not.

    – CiaPan
    Jan 29 '15 at 12:25






  • 1





    @JonathanMee: It's bad for all the reasons I mention: you cannot look into the future. You cannot tell what will happen in the future.

    – Kerrek SB
    Feb 3 '15 at 20:52






  • 2





    @JonathanMee: Yes, that would be appropriate, though usually you can combine this check into the operation (since most iostreams operations return the stream object, which itself has a boolean conversion), and that way you make it obvious that you're not ignoring the return value.

    – Kerrek SB
    Feb 3 '15 at 21:02






  • 1





    The std::cin and scanf examples happily treat bad input (something worth raising an error) as EOF (which just means leave the loop).

    – ex-bart
    Jul 31 '15 at 23:41












  • 26





    @CiaPan: I don't think that's true. Both C99 and C11 allow this.

    – Kerrek SB
    Jan 29 '15 at 12:10






  • 9





    But ANSI C does not.

    – CiaPan
    Jan 29 '15 at 12:25






  • 1





    @JonathanMee: It's bad for all the reasons I mention: you cannot look into the future. You cannot tell what will happen in the future.

    – Kerrek SB
    Feb 3 '15 at 20:52






  • 2





    @JonathanMee: Yes, that would be appropriate, though usually you can combine this check into the operation (since most iostreams operations return the stream object, which itself has a boolean conversion), and that way you make it obvious that you're not ignoring the return value.

    – Kerrek SB
    Feb 3 '15 at 21:02






  • 1





    The std::cin and scanf examples happily treat bad input (something worth raising an error) as EOF (which just means leave the loop).

    – ex-bart
    Jul 31 '15 at 23:41







26




26





@CiaPan: I don't think that's true. Both C99 and C11 allow this.

– Kerrek SB
Jan 29 '15 at 12:10





@CiaPan: I don't think that's true. Both C99 and C11 allow this.

– Kerrek SB
Jan 29 '15 at 12:10




9




9





But ANSI C does not.

– CiaPan
Jan 29 '15 at 12:25





But ANSI C does not.

– CiaPan
Jan 29 '15 at 12:25




1




1





@JonathanMee: It's bad for all the reasons I mention: you cannot look into the future. You cannot tell what will happen in the future.

– Kerrek SB
Feb 3 '15 at 20:52





@JonathanMee: It's bad for all the reasons I mention: you cannot look into the future. You cannot tell what will happen in the future.

– Kerrek SB
Feb 3 '15 at 20:52




2




2





@JonathanMee: Yes, that would be appropriate, though usually you can combine this check into the operation (since most iostreams operations return the stream object, which itself has a boolean conversion), and that way you make it obvious that you're not ignoring the return value.

– Kerrek SB
Feb 3 '15 at 21:02





@JonathanMee: Yes, that would be appropriate, though usually you can combine this check into the operation (since most iostreams operations return the stream object, which itself has a boolean conversion), and that way you make it obvious that you're not ignoring the return value.

– Kerrek SB
Feb 3 '15 at 21:02




1




1





The std::cin and scanf examples happily treat bad input (something worth raising an error) as EOF (which just means leave the loop).

– ex-bart
Jul 31 '15 at 23:41





The std::cin and scanf examples happily treat bad input (something worth raising an error) as EOF (which just means leave the loop).

– ex-bart
Jul 31 '15 at 23:41













218














It's wrong because (in the absence of a read error) it enters the loop one more time than the author expects. If there is a read error, the loop never terminates.



Consider the following code:



/* WARNING: demonstration of bad coding technique!! */

#include <stdio.h>
#include <stdlib.h>

FILE *Fopen(const char *path, const char *mode);

int main(int argc, char **argv)

FILE *in;
unsigned count;

in = argc > 1 ? Fopen(argv[1], "r") : stdin;
count = 0;

/* WARNING: this is a bug */
while (!feof(in)) /* This is WRONG! */
fgetc(in);
count++;

printf("Number of characters read: %un", count);
return EXIT_SUCCESS;


FILE * Fopen(const char *path, const char *mode)

FILE *f = fopen(path, mode);
if (f == NULL)
perror(path);
exit(EXIT_FAILURE);

return f;



This program will consistently print one greater than the number of characters in the input stream (assuming no read errors). Consider the case where the input stream is empty:



$ ./a.out < /dev/null
Number of characters read: 1


In this case, feof() is called before any data has been read, so it returns false. The loop is entered, fgetc() is called (and returns EOF), and count is incremented. Then feof() is called and returns true, causing the loop to abort.



This happens in all such cases. feof() does not return true until after a read on the stream encounters the end of file. The purpose of feof() is NOT to check if the next read will reach the end of file. The purpose of feof() is to distinguish between a read error and having reached the end of the file. If fread() returns 0, you must use feof/ferror to decide. Similarly if fgetc returns EOF. feof() is only useful after fread has returned zero or fgetc has returned EOF. Before that happens, feof() will always return 0.



It is always necessary to check the return value of a read (either an fread(), or an fscanf(), or an fgetc()) before calling feof().



Even worse, consider the case where a read error occurs. In that case, fgetc() returns EOF, feof() returns false, and the loop never terminates. In all cases where while(!feof(p)) is used, there must be at least a check inside the loop for ferror(), or at the very least the while condition should be replaced with while(!feof(p) && !ferror(p)) or there is a very real possibility of an infinite loop, probably spewing all sorts of garbage as invalid data is being processed.



So, in summary, although I cannot state with certainty that there is never a situation in which it may be semantically correct to write "while(!feof(f))" (although there must be another check inside the loop with a break to avoid a infinite loop on a read error), it is the case that it is almost certainly always wrong. And even if a case ever arose where it would be correct, it is so idiomatically wrong that it would not be the right way to write the code. Anyone seeing that code should immediately hesitate and say, "that's a bug". And possibly slap the author (unless the author is your boss in which case discretion is advised.)






share|improve this answer




















  • 16





    Mutlitple downvotes today: any explanation? If you disagree, please explain your reasons.

    – William Pursell
    Jun 5 '12 at 15:29






  • 6





    Sure it's wrong -- but aside from that it isn't "gratingly ugly".

    – nobar
    Jul 7 '13 at 0:53






  • 80





    You should add an example of correct code, as I imagine lots of people will come here looking for a quick fix.

    – jleahy
    Jul 12 '13 at 16:27






  • 2





    @Thomas: I'm not a C++ expert, but I believe file.eof() returns effectively the same result as feof(file) || ferror(file), so it is very different. But this question is not intended to be applicable to C++.

    – William Pursell
    Aug 26 '14 at 23:36






  • 6





    @m-ric that's not right either, because you'll still try to process a read that failed.

    – Mark Ransom
    Apr 9 '15 at 18:25















218














It's wrong because (in the absence of a read error) it enters the loop one more time than the author expects. If there is a read error, the loop never terminates.



Consider the following code:



/* WARNING: demonstration of bad coding technique!! */

#include <stdio.h>
#include <stdlib.h>

FILE *Fopen(const char *path, const char *mode);

int main(int argc, char **argv)

FILE *in;
unsigned count;

in = argc > 1 ? Fopen(argv[1], "r") : stdin;
count = 0;

/* WARNING: this is a bug */
while (!feof(in)) /* This is WRONG! */
fgetc(in);
count++;

printf("Number of characters read: %un", count);
return EXIT_SUCCESS;


FILE * Fopen(const char *path, const char *mode)

FILE *f = fopen(path, mode);
if (f == NULL)
perror(path);
exit(EXIT_FAILURE);

return f;



This program will consistently print one greater than the number of characters in the input stream (assuming no read errors). Consider the case where the input stream is empty:



$ ./a.out < /dev/null
Number of characters read: 1


In this case, feof() is called before any data has been read, so it returns false. The loop is entered, fgetc() is called (and returns EOF), and count is incremented. Then feof() is called and returns true, causing the loop to abort.



This happens in all such cases. feof() does not return true until after a read on the stream encounters the end of file. The purpose of feof() is NOT to check if the next read will reach the end of file. The purpose of feof() is to distinguish between a read error and having reached the end of the file. If fread() returns 0, you must use feof/ferror to decide. Similarly if fgetc returns EOF. feof() is only useful after fread has returned zero or fgetc has returned EOF. Before that happens, feof() will always return 0.



It is always necessary to check the return value of a read (either an fread(), or an fscanf(), or an fgetc()) before calling feof().



Even worse, consider the case where a read error occurs. In that case, fgetc() returns EOF, feof() returns false, and the loop never terminates. In all cases where while(!feof(p)) is used, there must be at least a check inside the loop for ferror(), or at the very least the while condition should be replaced with while(!feof(p) && !ferror(p)) or there is a very real possibility of an infinite loop, probably spewing all sorts of garbage as invalid data is being processed.



So, in summary, although I cannot state with certainty that there is never a situation in which it may be semantically correct to write "while(!feof(f))" (although there must be another check inside the loop with a break to avoid a infinite loop on a read error), it is the case that it is almost certainly always wrong. And even if a case ever arose where it would be correct, it is so idiomatically wrong that it would not be the right way to write the code. Anyone seeing that code should immediately hesitate and say, "that's a bug". And possibly slap the author (unless the author is your boss in which case discretion is advised.)






share|improve this answer




















  • 16





    Mutlitple downvotes today: any explanation? If you disagree, please explain your reasons.

    – William Pursell
    Jun 5 '12 at 15:29






  • 6





    Sure it's wrong -- but aside from that it isn't "gratingly ugly".

    – nobar
    Jul 7 '13 at 0:53






  • 80





    You should add an example of correct code, as I imagine lots of people will come here looking for a quick fix.

    – jleahy
    Jul 12 '13 at 16:27






  • 2





    @Thomas: I'm not a C++ expert, but I believe file.eof() returns effectively the same result as feof(file) || ferror(file), so it is very different. But this question is not intended to be applicable to C++.

    – William Pursell
    Aug 26 '14 at 23:36






  • 6





    @m-ric that's not right either, because you'll still try to process a read that failed.

    – Mark Ransom
    Apr 9 '15 at 18:25













218












218








218







It's wrong because (in the absence of a read error) it enters the loop one more time than the author expects. If there is a read error, the loop never terminates.



Consider the following code:



/* WARNING: demonstration of bad coding technique!! */

#include <stdio.h>
#include <stdlib.h>

FILE *Fopen(const char *path, const char *mode);

int main(int argc, char **argv)

FILE *in;
unsigned count;

in = argc > 1 ? Fopen(argv[1], "r") : stdin;
count = 0;

/* WARNING: this is a bug */
while (!feof(in)) /* This is WRONG! */
fgetc(in);
count++;

printf("Number of characters read: %un", count);
return EXIT_SUCCESS;


FILE * Fopen(const char *path, const char *mode)

FILE *f = fopen(path, mode);
if (f == NULL)
perror(path);
exit(EXIT_FAILURE);

return f;



This program will consistently print one greater than the number of characters in the input stream (assuming no read errors). Consider the case where the input stream is empty:



$ ./a.out < /dev/null
Number of characters read: 1


In this case, feof() is called before any data has been read, so it returns false. The loop is entered, fgetc() is called (and returns EOF), and count is incremented. Then feof() is called and returns true, causing the loop to abort.



This happens in all such cases. feof() does not return true until after a read on the stream encounters the end of file. The purpose of feof() is NOT to check if the next read will reach the end of file. The purpose of feof() is to distinguish between a read error and having reached the end of the file. If fread() returns 0, you must use feof/ferror to decide. Similarly if fgetc returns EOF. feof() is only useful after fread has returned zero or fgetc has returned EOF. Before that happens, feof() will always return 0.



It is always necessary to check the return value of a read (either an fread(), or an fscanf(), or an fgetc()) before calling feof().



Even worse, consider the case where a read error occurs. In that case, fgetc() returns EOF, feof() returns false, and the loop never terminates. In all cases where while(!feof(p)) is used, there must be at least a check inside the loop for ferror(), or at the very least the while condition should be replaced with while(!feof(p) && !ferror(p)) or there is a very real possibility of an infinite loop, probably spewing all sorts of garbage as invalid data is being processed.



So, in summary, although I cannot state with certainty that there is never a situation in which it may be semantically correct to write "while(!feof(f))" (although there must be another check inside the loop with a break to avoid a infinite loop on a read error), it is the case that it is almost certainly always wrong. And even if a case ever arose where it would be correct, it is so idiomatically wrong that it would not be the right way to write the code. Anyone seeing that code should immediately hesitate and say, "that's a bug". And possibly slap the author (unless the author is your boss in which case discretion is advised.)






share|improve this answer















It's wrong because (in the absence of a read error) it enters the loop one more time than the author expects. If there is a read error, the loop never terminates.



Consider the following code:



/* WARNING: demonstration of bad coding technique!! */

#include <stdio.h>
#include <stdlib.h>

FILE *Fopen(const char *path, const char *mode);

int main(int argc, char **argv)

FILE *in;
unsigned count;

in = argc > 1 ? Fopen(argv[1], "r") : stdin;
count = 0;

/* WARNING: this is a bug */
while (!feof(in)) /* This is WRONG! */
fgetc(in);
count++;

printf("Number of characters read: %un", count);
return EXIT_SUCCESS;


FILE * Fopen(const char *path, const char *mode)

FILE *f = fopen(path, mode);
if (f == NULL)
perror(path);
exit(EXIT_FAILURE);

return f;



This program will consistently print one greater than the number of characters in the input stream (assuming no read errors). Consider the case where the input stream is empty:



$ ./a.out < /dev/null
Number of characters read: 1


In this case, feof() is called before any data has been read, so it returns false. The loop is entered, fgetc() is called (and returns EOF), and count is incremented. Then feof() is called and returns true, causing the loop to abort.



This happens in all such cases. feof() does not return true until after a read on the stream encounters the end of file. The purpose of feof() is NOT to check if the next read will reach the end of file. The purpose of feof() is to distinguish between a read error and having reached the end of the file. If fread() returns 0, you must use feof/ferror to decide. Similarly if fgetc returns EOF. feof() is only useful after fread has returned zero or fgetc has returned EOF. Before that happens, feof() will always return 0.



It is always necessary to check the return value of a read (either an fread(), or an fscanf(), or an fgetc()) before calling feof().



Even worse, consider the case where a read error occurs. In that case, fgetc() returns EOF, feof() returns false, and the loop never terminates. In all cases where while(!feof(p)) is used, there must be at least a check inside the loop for ferror(), or at the very least the while condition should be replaced with while(!feof(p) && !ferror(p)) or there is a very real possibility of an infinite loop, probably spewing all sorts of garbage as invalid data is being processed.



So, in summary, although I cannot state with certainty that there is never a situation in which it may be semantically correct to write "while(!feof(f))" (although there must be another check inside the loop with a break to avoid a infinite loop on a read error), it is the case that it is almost certainly always wrong. And even if a case ever arose where it would be correct, it is so idiomatically wrong that it would not be the right way to write the code. Anyone seeing that code should immediately hesitate and say, "that's a bug". And possibly slap the author (unless the author is your boss in which case discretion is advised.)







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 13 '18 at 15:12

























answered Mar 25 '11 at 12:39









William PursellWilliam Pursell

136k36213245




136k36213245







  • 16





    Mutlitple downvotes today: any explanation? If you disagree, please explain your reasons.

    – William Pursell
    Jun 5 '12 at 15:29






  • 6





    Sure it's wrong -- but aside from that it isn't "gratingly ugly".

    – nobar
    Jul 7 '13 at 0:53






  • 80





    You should add an example of correct code, as I imagine lots of people will come here looking for a quick fix.

    – jleahy
    Jul 12 '13 at 16:27






  • 2





    @Thomas: I'm not a C++ expert, but I believe file.eof() returns effectively the same result as feof(file) || ferror(file), so it is very different. But this question is not intended to be applicable to C++.

    – William Pursell
    Aug 26 '14 at 23:36






  • 6





    @m-ric that's not right either, because you'll still try to process a read that failed.

    – Mark Ransom
    Apr 9 '15 at 18:25












  • 16





    Mutlitple downvotes today: any explanation? If you disagree, please explain your reasons.

    – William Pursell
    Jun 5 '12 at 15:29






  • 6





    Sure it's wrong -- but aside from that it isn't "gratingly ugly".

    – nobar
    Jul 7 '13 at 0:53






  • 80





    You should add an example of correct code, as I imagine lots of people will come here looking for a quick fix.

    – jleahy
    Jul 12 '13 at 16:27






  • 2





    @Thomas: I'm not a C++ expert, but I believe file.eof() returns effectively the same result as feof(file) || ferror(file), so it is very different. But this question is not intended to be applicable to C++.

    – William Pursell
    Aug 26 '14 at 23:36






  • 6





    @m-ric that's not right either, because you'll still try to process a read that failed.

    – Mark Ransom
    Apr 9 '15 at 18:25







16




16





Mutlitple downvotes today: any explanation? If you disagree, please explain your reasons.

– William Pursell
Jun 5 '12 at 15:29





Mutlitple downvotes today: any explanation? If you disagree, please explain your reasons.

– William Pursell
Jun 5 '12 at 15:29




6




6





Sure it's wrong -- but aside from that it isn't "gratingly ugly".

– nobar
Jul 7 '13 at 0:53





Sure it's wrong -- but aside from that it isn't "gratingly ugly".

– nobar
Jul 7 '13 at 0:53




80




80





You should add an example of correct code, as I imagine lots of people will come here looking for a quick fix.

– jleahy
Jul 12 '13 at 16:27





You should add an example of correct code, as I imagine lots of people will come here looking for a quick fix.

– jleahy
Jul 12 '13 at 16:27




2




2





@Thomas: I'm not a C++ expert, but I believe file.eof() returns effectively the same result as feof(file) || ferror(file), so it is very different. But this question is not intended to be applicable to C++.

– William Pursell
Aug 26 '14 at 23:36





@Thomas: I'm not a C++ expert, but I believe file.eof() returns effectively the same result as feof(file) || ferror(file), so it is very different. But this question is not intended to be applicable to C++.

– William Pursell
Aug 26 '14 at 23:36




6




6





@m-ric that's not right either, because you'll still try to process a read that failed.

– Mark Ransom
Apr 9 '15 at 18:25





@m-ric that's not right either, because you'll still try to process a read that failed.

– Mark Ransom
Apr 9 '15 at 18:25











60














No it's not always wrong. If your loop condition is "while we haven't tried to read past end of file" then you use while (!feof(f)). This is however not a common loop condition - usually you want to test for something else (such as "can I read more"). while (!feof(f)) isn't wrong, it's just used wrong.






share|improve this answer


















  • 1





    I wonder ... f = fopen("A:\bigfile"); while (!feof(f)) /* remove diskette */ or (going to test this) f = fopen(NETWORK_FILE); while (!feof(f)) /* unplug network cable */

    – pmg
    Mar 25 '11 at 11:53







  • 1





    @pmg: As said, "not a common loop condition" hehe. I can't really think of any case I've needed it, usually I'm interested in "could I read what I wanted" with all that implies of error handling

    – Erik
    Mar 25 '11 at 11:56











  • @pmg: As said, you rarely want while(!eof(f))

    – Erik
    Mar 25 '11 at 12:41






  • 7





    More accurately, the condition is "while we haven't tried to read past the end of the file and there was no read error" feof is not about detecting end of file; it is about determining whether a read was short because of an error or because the input is exhausted.

    – William Pursell
    Jul 3 '13 at 15:18















60














No it's not always wrong. If your loop condition is "while we haven't tried to read past end of file" then you use while (!feof(f)). This is however not a common loop condition - usually you want to test for something else (such as "can I read more"). while (!feof(f)) isn't wrong, it's just used wrong.






share|improve this answer


















  • 1





    I wonder ... f = fopen("A:\bigfile"); while (!feof(f)) /* remove diskette */ or (going to test this) f = fopen(NETWORK_FILE); while (!feof(f)) /* unplug network cable */

    – pmg
    Mar 25 '11 at 11:53







  • 1





    @pmg: As said, "not a common loop condition" hehe. I can't really think of any case I've needed it, usually I'm interested in "could I read what I wanted" with all that implies of error handling

    – Erik
    Mar 25 '11 at 11:56











  • @pmg: As said, you rarely want while(!eof(f))

    – Erik
    Mar 25 '11 at 12:41






  • 7





    More accurately, the condition is "while we haven't tried to read past the end of the file and there was no read error" feof is not about detecting end of file; it is about determining whether a read was short because of an error or because the input is exhausted.

    – William Pursell
    Jul 3 '13 at 15:18













60












60








60







No it's not always wrong. If your loop condition is "while we haven't tried to read past end of file" then you use while (!feof(f)). This is however not a common loop condition - usually you want to test for something else (such as "can I read more"). while (!feof(f)) isn't wrong, it's just used wrong.






share|improve this answer













No it's not always wrong. If your loop condition is "while we haven't tried to read past end of file" then you use while (!feof(f)). This is however not a common loop condition - usually you want to test for something else (such as "can I read more"). while (!feof(f)) isn't wrong, it's just used wrong.







share|improve this answer












share|improve this answer



share|improve this answer










answered Mar 25 '11 at 11:49









ErikErik

69.3k10174175




69.3k10174175







  • 1





    I wonder ... f = fopen("A:\bigfile"); while (!feof(f)) /* remove diskette */ or (going to test this) f = fopen(NETWORK_FILE); while (!feof(f)) /* unplug network cable */

    – pmg
    Mar 25 '11 at 11:53







  • 1





    @pmg: As said, "not a common loop condition" hehe. I can't really think of any case I've needed it, usually I'm interested in "could I read what I wanted" with all that implies of error handling

    – Erik
    Mar 25 '11 at 11:56











  • @pmg: As said, you rarely want while(!eof(f))

    – Erik
    Mar 25 '11 at 12:41






  • 7





    More accurately, the condition is "while we haven't tried to read past the end of the file and there was no read error" feof is not about detecting end of file; it is about determining whether a read was short because of an error or because the input is exhausted.

    – William Pursell
    Jul 3 '13 at 15:18












  • 1





    I wonder ... f = fopen("A:\bigfile"); while (!feof(f)) /* remove diskette */ or (going to test this) f = fopen(NETWORK_FILE); while (!feof(f)) /* unplug network cable */

    – pmg
    Mar 25 '11 at 11:53







  • 1





    @pmg: As said, "not a common loop condition" hehe. I can't really think of any case I've needed it, usually I'm interested in "could I read what I wanted" with all that implies of error handling

    – Erik
    Mar 25 '11 at 11:56











  • @pmg: As said, you rarely want while(!eof(f))

    – Erik
    Mar 25 '11 at 12:41






  • 7





    More accurately, the condition is "while we haven't tried to read past the end of the file and there was no read error" feof is not about detecting end of file; it is about determining whether a read was short because of an error or because the input is exhausted.

    – William Pursell
    Jul 3 '13 at 15:18







1




1





I wonder ... f = fopen("A:\bigfile"); while (!feof(f)) /* remove diskette */ or (going to test this) f = fopen(NETWORK_FILE); while (!feof(f)) /* unplug network cable */

– pmg
Mar 25 '11 at 11:53






I wonder ... f = fopen("A:\bigfile"); while (!feof(f)) /* remove diskette */ or (going to test this) f = fopen(NETWORK_FILE); while (!feof(f)) /* unplug network cable */

– pmg
Mar 25 '11 at 11:53





1




1





@pmg: As said, "not a common loop condition" hehe. I can't really think of any case I've needed it, usually I'm interested in "could I read what I wanted" with all that implies of error handling

– Erik
Mar 25 '11 at 11:56





@pmg: As said, "not a common loop condition" hehe. I can't really think of any case I've needed it, usually I'm interested in "could I read what I wanted" with all that implies of error handling

– Erik
Mar 25 '11 at 11:56













@pmg: As said, you rarely want while(!eof(f))

– Erik
Mar 25 '11 at 12:41





@pmg: As said, you rarely want while(!eof(f))

– Erik
Mar 25 '11 at 12:41




7




7





More accurately, the condition is "while we haven't tried to read past the end of the file and there was no read error" feof is not about detecting end of file; it is about determining whether a read was short because of an error or because the input is exhausted.

– William Pursell
Jul 3 '13 at 15:18





More accurately, the condition is "while we haven't tried to read past the end of the file and there was no read error" feof is not about detecting end of file; it is about determining whether a read was short because of an error or because the input is exhausted.

– William Pursell
Jul 3 '13 at 15:18











29














feof() indicates if one has tried to read past the end of file. That means it has little predictive effect: if it is true, you are sure that the next input operation will fail (you aren't sure the previous one failed BTW), but if it is false, you aren't sure the next input operation will succeed. More over, input operations may fail for other reasons than the end of file (a format error for formatted input, a pure IO failure -- disk failure, network timeout -- for all input kinds), so even if you could be predictive about the end of file (and anybody who has tried to implement Ada one, which is predictive, will tell you it can complex if you need to skip spaces, and that it has undesirable effects on interactive devices -- sometimes forcing the input of the next line before starting the handling of the previous one), you would have to be able to handle a failure.



So the correct idiom in C is to loop with the IO operation success as loop condition, and then test the cause of the failure. For instance:



while (fgets(line, sizeof(line), file)) 
/* note that fgets don't strip the terminating n, checking its
presence allow to handle lines longer that sizeof(line), not showed here */
...

if (ferror(file))
/* IO failure */
else if (feof(file))
/* format error (not possible with fgets, but would be with fscanf) or end of file */
else
/* format error (not possible with fgets, but would be with fscanf) */






share|improve this answer


















  • 2





    Getting to the end of a file is not an error, so I question the phrasing "input operations may fail for other reasons than the end of file".

    – William Pursell
    Sep 29 '12 at 12:59











  • @WilliamPursell, reaching the eof isn't necessarily an error, but being unable to do an input operation because of eof is one. And it is impossible in C to detect reliably the eof without having made an input operation fails.

    – AProgrammer
    Sep 29 '12 at 15:12











  • Agree last else not possible with sizeof(line) >= 2 and fgets(line, sizeof(line), file) but possible with pathological size <= 0 and fgets(line, size, file). Maybe even possible with sizeof(line) == 1.

    – chux
    Mar 26 '15 at 21:21











  • All that "predictive value" talk... I never thought about it that way. In my world, feof(f) does not PREDICT anything. It states that a PREVIOUS operation has hit the end of the file. Nothing more, nothing less. And if there was no previous operation (just opened it), it does not report end of file even if the file was empty to start with. So, apart of the concurrency explanation in another answer above, I do not think there is any reason not to loop on feof(f).

    – BitTickler
    Sep 24 '17 at 20:36











  • @AProgrammer: A "read up to N bytes" request that yields zero, whether because of a "permanent" EOF or because no more data is available yet, is not an error. While feof() may not reliably predict that future requests will yield data, it may reliably indicate that future requests won't. Perhaps there should be a status function that would indicate "It is plausible that future read requests will succeed", with semantics that after reading to the end of an ordinary file, a quality implementation should say future reads are unlikely to succeed absent some reason to believe they might.

    – supercat
    Feb 3 at 15:49
















29














feof() indicates if one has tried to read past the end of file. That means it has little predictive effect: if it is true, you are sure that the next input operation will fail (you aren't sure the previous one failed BTW), but if it is false, you aren't sure the next input operation will succeed. More over, input operations may fail for other reasons than the end of file (a format error for formatted input, a pure IO failure -- disk failure, network timeout -- for all input kinds), so even if you could be predictive about the end of file (and anybody who has tried to implement Ada one, which is predictive, will tell you it can complex if you need to skip spaces, and that it has undesirable effects on interactive devices -- sometimes forcing the input of the next line before starting the handling of the previous one), you would have to be able to handle a failure.



So the correct idiom in C is to loop with the IO operation success as loop condition, and then test the cause of the failure. For instance:



while (fgets(line, sizeof(line), file)) 
/* note that fgets don't strip the terminating n, checking its
presence allow to handle lines longer that sizeof(line), not showed here */
...

if (ferror(file))
/* IO failure */
else if (feof(file))
/* format error (not possible with fgets, but would be with fscanf) or end of file */
else
/* format error (not possible with fgets, but would be with fscanf) */






share|improve this answer


















  • 2





    Getting to the end of a file is not an error, so I question the phrasing "input operations may fail for other reasons than the end of file".

    – William Pursell
    Sep 29 '12 at 12:59











  • @WilliamPursell, reaching the eof isn't necessarily an error, but being unable to do an input operation because of eof is one. And it is impossible in C to detect reliably the eof without having made an input operation fails.

    – AProgrammer
    Sep 29 '12 at 15:12











  • Agree last else not possible with sizeof(line) >= 2 and fgets(line, sizeof(line), file) but possible with pathological size <= 0 and fgets(line, size, file). Maybe even possible with sizeof(line) == 1.

    – chux
    Mar 26 '15 at 21:21











  • All that "predictive value" talk... I never thought about it that way. In my world, feof(f) does not PREDICT anything. It states that a PREVIOUS operation has hit the end of the file. Nothing more, nothing less. And if there was no previous operation (just opened it), it does not report end of file even if the file was empty to start with. So, apart of the concurrency explanation in another answer above, I do not think there is any reason not to loop on feof(f).

    – BitTickler
    Sep 24 '17 at 20:36











  • @AProgrammer: A "read up to N bytes" request that yields zero, whether because of a "permanent" EOF or because no more data is available yet, is not an error. While feof() may not reliably predict that future requests will yield data, it may reliably indicate that future requests won't. Perhaps there should be a status function that would indicate "It is plausible that future read requests will succeed", with semantics that after reading to the end of an ordinary file, a quality implementation should say future reads are unlikely to succeed absent some reason to believe they might.

    – supercat
    Feb 3 at 15:49














29












29








29







feof() indicates if one has tried to read past the end of file. That means it has little predictive effect: if it is true, you are sure that the next input operation will fail (you aren't sure the previous one failed BTW), but if it is false, you aren't sure the next input operation will succeed. More over, input operations may fail for other reasons than the end of file (a format error for formatted input, a pure IO failure -- disk failure, network timeout -- for all input kinds), so even if you could be predictive about the end of file (and anybody who has tried to implement Ada one, which is predictive, will tell you it can complex if you need to skip spaces, and that it has undesirable effects on interactive devices -- sometimes forcing the input of the next line before starting the handling of the previous one), you would have to be able to handle a failure.



So the correct idiom in C is to loop with the IO operation success as loop condition, and then test the cause of the failure. For instance:



while (fgets(line, sizeof(line), file)) 
/* note that fgets don't strip the terminating n, checking its
presence allow to handle lines longer that sizeof(line), not showed here */
...

if (ferror(file))
/* IO failure */
else if (feof(file))
/* format error (not possible with fgets, but would be with fscanf) or end of file */
else
/* format error (not possible with fgets, but would be with fscanf) */






share|improve this answer













feof() indicates if one has tried to read past the end of file. That means it has little predictive effect: if it is true, you are sure that the next input operation will fail (you aren't sure the previous one failed BTW), but if it is false, you aren't sure the next input operation will succeed. More over, input operations may fail for other reasons than the end of file (a format error for formatted input, a pure IO failure -- disk failure, network timeout -- for all input kinds), so even if you could be predictive about the end of file (and anybody who has tried to implement Ada one, which is predictive, will tell you it can complex if you need to skip spaces, and that it has undesirable effects on interactive devices -- sometimes forcing the input of the next line before starting the handling of the previous one), you would have to be able to handle a failure.



So the correct idiom in C is to loop with the IO operation success as loop condition, and then test the cause of the failure. For instance:



while (fgets(line, sizeof(line), file)) 
/* note that fgets don't strip the terminating n, checking its
presence allow to handle lines longer that sizeof(line), not showed here */
...

if (ferror(file))
/* IO failure */
else if (feof(file))
/* format error (not possible with fgets, but would be with fscanf) or end of file */
else
/* format error (not possible with fgets, but would be with fscanf) */







share|improve this answer












share|improve this answer



share|improve this answer










answered Feb 10 '12 at 10:22









AProgrammerAProgrammer

43.6k773127




43.6k773127







  • 2





    Getting to the end of a file is not an error, so I question the phrasing "input operations may fail for other reasons than the end of file".

    – William Pursell
    Sep 29 '12 at 12:59











  • @WilliamPursell, reaching the eof isn't necessarily an error, but being unable to do an input operation because of eof is one. And it is impossible in C to detect reliably the eof without having made an input operation fails.

    – AProgrammer
    Sep 29 '12 at 15:12











  • Agree last else not possible with sizeof(line) >= 2 and fgets(line, sizeof(line), file) but possible with pathological size <= 0 and fgets(line, size, file). Maybe even possible with sizeof(line) == 1.

    – chux
    Mar 26 '15 at 21:21











  • All that "predictive value" talk... I never thought about it that way. In my world, feof(f) does not PREDICT anything. It states that a PREVIOUS operation has hit the end of the file. Nothing more, nothing less. And if there was no previous operation (just opened it), it does not report end of file even if the file was empty to start with. So, apart of the concurrency explanation in another answer above, I do not think there is any reason not to loop on feof(f).

    – BitTickler
    Sep 24 '17 at 20:36











  • @AProgrammer: A "read up to N bytes" request that yields zero, whether because of a "permanent" EOF or because no more data is available yet, is not an error. While feof() may not reliably predict that future requests will yield data, it may reliably indicate that future requests won't. Perhaps there should be a status function that would indicate "It is plausible that future read requests will succeed", with semantics that after reading to the end of an ordinary file, a quality implementation should say future reads are unlikely to succeed absent some reason to believe they might.

    – supercat
    Feb 3 at 15:49













  • 2





    Getting to the end of a file is not an error, so I question the phrasing "input operations may fail for other reasons than the end of file".

    – William Pursell
    Sep 29 '12 at 12:59











  • @WilliamPursell, reaching the eof isn't necessarily an error, but being unable to do an input operation because of eof is one. And it is impossible in C to detect reliably the eof without having made an input operation fails.

    – AProgrammer
    Sep 29 '12 at 15:12











  • Agree last else not possible with sizeof(line) >= 2 and fgets(line, sizeof(line), file) but possible with pathological size <= 0 and fgets(line, size, file). Maybe even possible with sizeof(line) == 1.

    – chux
    Mar 26 '15 at 21:21











  • All that "predictive value" talk... I never thought about it that way. In my world, feof(f) does not PREDICT anything. It states that a PREVIOUS operation has hit the end of the file. Nothing more, nothing less. And if there was no previous operation (just opened it), it does not report end of file even if the file was empty to start with. So, apart of the concurrency explanation in another answer above, I do not think there is any reason not to loop on feof(f).

    – BitTickler
    Sep 24 '17 at 20:36











  • @AProgrammer: A "read up to N bytes" request that yields zero, whether because of a "permanent" EOF or because no more data is available yet, is not an error. While feof() may not reliably predict that future requests will yield data, it may reliably indicate that future requests won't. Perhaps there should be a status function that would indicate "It is plausible that future read requests will succeed", with semantics that after reading to the end of an ordinary file, a quality implementation should say future reads are unlikely to succeed absent some reason to believe they might.

    – supercat
    Feb 3 at 15:49








2




2





Getting to the end of a file is not an error, so I question the phrasing "input operations may fail for other reasons than the end of file".

– William Pursell
Sep 29 '12 at 12:59





Getting to the end of a file is not an error, so I question the phrasing "input operations may fail for other reasons than the end of file".

– William Pursell
Sep 29 '12 at 12:59













@WilliamPursell, reaching the eof isn't necessarily an error, but being unable to do an input operation because of eof is one. And it is impossible in C to detect reliably the eof without having made an input operation fails.

– AProgrammer
Sep 29 '12 at 15:12





@WilliamPursell, reaching the eof isn't necessarily an error, but being unable to do an input operation because of eof is one. And it is impossible in C to detect reliably the eof without having made an input operation fails.

– AProgrammer
Sep 29 '12 at 15:12













Agree last else not possible with sizeof(line) >= 2 and fgets(line, sizeof(line), file) but possible with pathological size <= 0 and fgets(line, size, file). Maybe even possible with sizeof(line) == 1.

– chux
Mar 26 '15 at 21:21





Agree last else not possible with sizeof(line) >= 2 and fgets(line, sizeof(line), file) but possible with pathological size <= 0 and fgets(line, size, file). Maybe even possible with sizeof(line) == 1.

– chux
Mar 26 '15 at 21:21













All that "predictive value" talk... I never thought about it that way. In my world, feof(f) does not PREDICT anything. It states that a PREVIOUS operation has hit the end of the file. Nothing more, nothing less. And if there was no previous operation (just opened it), it does not report end of file even if the file was empty to start with. So, apart of the concurrency explanation in another answer above, I do not think there is any reason not to loop on feof(f).

– BitTickler
Sep 24 '17 at 20:36





All that "predictive value" talk... I never thought about it that way. In my world, feof(f) does not PREDICT anything. It states that a PREVIOUS operation has hit the end of the file. Nothing more, nothing less. And if there was no previous operation (just opened it), it does not report end of file even if the file was empty to start with. So, apart of the concurrency explanation in another answer above, I do not think there is any reason not to loop on feof(f).

– BitTickler
Sep 24 '17 at 20:36













@AProgrammer: A "read up to N bytes" request that yields zero, whether because of a "permanent" EOF or because no more data is available yet, is not an error. While feof() may not reliably predict that future requests will yield data, it may reliably indicate that future requests won't. Perhaps there should be a status function that would indicate "It is plausible that future read requests will succeed", with semantics that after reading to the end of an ordinary file, a quality implementation should say future reads are unlikely to succeed absent some reason to believe they might.

– supercat
Feb 3 at 15:49






@AProgrammer: A "read up to N bytes" request that yields zero, whether because of a "permanent" EOF or because no more data is available yet, is not an error. While feof() may not reliably predict that future requests will yield data, it may reliably indicate that future requests won't. Perhaps there should be a status function that would indicate "It is plausible that future read requests will succeed", with semantics that after reading to the end of an ordinary file, a quality implementation should say future reads are unlikely to succeed absent some reason to believe they might.

– supercat
Feb 3 at 15:49












10














Great answer, I just noticed the same thing because I was trying to do a loop like that. So, it's wrong in that scenario, but if you want to have a loop that gracefully ends at the EOF, this is a nice way to do it:



#include <stdio.h>
#include <sys/stat.h>
int main(int argc, char *argv[])

struct stat buf;
FILE *fp = fopen(argv[0], "r");
stat(filename, &buf);
while (ftello(fp) != buf.st_size)
(void)fgetc(fp);

// all done, read all the bytes






share|improve this answer

























  • This is an interesting approach, but does not work on a fifo. It doesn't seem to offer any benefit over while( fgetc(fp) != EOF )

    – William Pursell
    Jun 2 '13 at 11:34






  • 1





    True, but sometimes you don't use fgetc() to read files. For example, reading structured records, I have a read function (in this example where there's a fgetc) which detects errors and reads exactly one record, but it doesn't know how many records are in the file. Yes, it's wrong for fifos, or any other file that might change while you have it open.

    – tesch1
    Jun 3 '13 at 2:46












  • while( read_structured_record( fp ) == 1 ) { ... would be an idiomatic way to write that (assuming read_structured_record returns the number of records read).

    – William Pursell
    Jun 3 '13 at 13:38







  • 1





    File I/O errors may happen anytime, thus by not checking the result of fgetc(fp), one may miss that and not read all the bytes.

    – chux
    Sep 13 '13 at 17:47






  • 1





    Files can grow while you are reading them; they can also shrink. The size given by the one-time stat() operation is not reliable over the long term.

    – Jonathan Leffler
    Mar 26 '15 at 17:55















10














Great answer, I just noticed the same thing because I was trying to do a loop like that. So, it's wrong in that scenario, but if you want to have a loop that gracefully ends at the EOF, this is a nice way to do it:



#include <stdio.h>
#include <sys/stat.h>
int main(int argc, char *argv[])

struct stat buf;
FILE *fp = fopen(argv[0], "r");
stat(filename, &buf);
while (ftello(fp) != buf.st_size)
(void)fgetc(fp);

// all done, read all the bytes






share|improve this answer

























  • This is an interesting approach, but does not work on a fifo. It doesn't seem to offer any benefit over while( fgetc(fp) != EOF )

    – William Pursell
    Jun 2 '13 at 11:34






  • 1





    True, but sometimes you don't use fgetc() to read files. For example, reading structured records, I have a read function (in this example where there's a fgetc) which detects errors and reads exactly one record, but it doesn't know how many records are in the file. Yes, it's wrong for fifos, or any other file that might change while you have it open.

    – tesch1
    Jun 3 '13 at 2:46












  • while( read_structured_record( fp ) == 1 ) { ... would be an idiomatic way to write that (assuming read_structured_record returns the number of records read).

    – William Pursell
    Jun 3 '13 at 13:38







  • 1





    File I/O errors may happen anytime, thus by not checking the result of fgetc(fp), one may miss that and not read all the bytes.

    – chux
    Sep 13 '13 at 17:47






  • 1





    Files can grow while you are reading them; they can also shrink. The size given by the one-time stat() operation is not reliable over the long term.

    – Jonathan Leffler
    Mar 26 '15 at 17:55













10












10








10







Great answer, I just noticed the same thing because I was trying to do a loop like that. So, it's wrong in that scenario, but if you want to have a loop that gracefully ends at the EOF, this is a nice way to do it:



#include <stdio.h>
#include <sys/stat.h>
int main(int argc, char *argv[])

struct stat buf;
FILE *fp = fopen(argv[0], "r");
stat(filename, &buf);
while (ftello(fp) != buf.st_size)
(void)fgetc(fp);

// all done, read all the bytes






share|improve this answer















Great answer, I just noticed the same thing because I was trying to do a loop like that. So, it's wrong in that scenario, but if you want to have a loop that gracefully ends at the EOF, this is a nice way to do it:



#include <stdio.h>
#include <sys/stat.h>
int main(int argc, char *argv[])

struct stat buf;
FILE *fp = fopen(argv[0], "r");
stat(filename, &buf);
while (ftello(fp) != buf.st_size)
(void)fgetc(fp);

// all done, read all the bytes







share|improve this answer














share|improve this answer



share|improve this answer








edited Jun 3 '13 at 2:47

























answered Jun 2 '13 at 1:43









tesch1tesch1

1,5971911




1,5971911












  • This is an interesting approach, but does not work on a fifo. It doesn't seem to offer any benefit over while( fgetc(fp) != EOF )

    – William Pursell
    Jun 2 '13 at 11:34






  • 1





    True, but sometimes you don't use fgetc() to read files. For example, reading structured records, I have a read function (in this example where there's a fgetc) which detects errors and reads exactly one record, but it doesn't know how many records are in the file. Yes, it's wrong for fifos, or any other file that might change while you have it open.

    – tesch1
    Jun 3 '13 at 2:46












  • while( read_structured_record( fp ) == 1 ) { ... would be an idiomatic way to write that (assuming read_structured_record returns the number of records read).

    – William Pursell
    Jun 3 '13 at 13:38







  • 1





    File I/O errors may happen anytime, thus by not checking the result of fgetc(fp), one may miss that and not read all the bytes.

    – chux
    Sep 13 '13 at 17:47






  • 1





    Files can grow while you are reading them; they can also shrink. The size given by the one-time stat() operation is not reliable over the long term.

    – Jonathan Leffler
    Mar 26 '15 at 17:55

















  • This is an interesting approach, but does not work on a fifo. It doesn't seem to offer any benefit over while( fgetc(fp) != EOF )

    – William Pursell
    Jun 2 '13 at 11:34






  • 1





    True, but sometimes you don't use fgetc() to read files. For example, reading structured records, I have a read function (in this example where there's a fgetc) which detects errors and reads exactly one record, but it doesn't know how many records are in the file. Yes, it's wrong for fifos, or any other file that might change while you have it open.

    – tesch1
    Jun 3 '13 at 2:46












  • while( read_structured_record( fp ) == 1 ) { ... would be an idiomatic way to write that (assuming read_structured_record returns the number of records read).

    – William Pursell
    Jun 3 '13 at 13:38







  • 1





    File I/O errors may happen anytime, thus by not checking the result of fgetc(fp), one may miss that and not read all the bytes.

    – chux
    Sep 13 '13 at 17:47






  • 1





    Files can grow while you are reading them; they can also shrink. The size given by the one-time stat() operation is not reliable over the long term.

    – Jonathan Leffler
    Mar 26 '15 at 17:55
















This is an interesting approach, but does not work on a fifo. It doesn't seem to offer any benefit over while( fgetc(fp) != EOF )

– William Pursell
Jun 2 '13 at 11:34





This is an interesting approach, but does not work on a fifo. It doesn't seem to offer any benefit over while( fgetc(fp) != EOF )

– William Pursell
Jun 2 '13 at 11:34




1




1





True, but sometimes you don't use fgetc() to read files. For example, reading structured records, I have a read function (in this example where there's a fgetc) which detects errors and reads exactly one record, but it doesn't know how many records are in the file. Yes, it's wrong for fifos, or any other file that might change while you have it open.

– tesch1
Jun 3 '13 at 2:46






True, but sometimes you don't use fgetc() to read files. For example, reading structured records, I have a read function (in this example where there's a fgetc) which detects errors and reads exactly one record, but it doesn't know how many records are in the file. Yes, it's wrong for fifos, or any other file that might change while you have it open.

– tesch1
Jun 3 '13 at 2:46














while( read_structured_record( fp ) == 1 ) { ... would be an idiomatic way to write that (assuming read_structured_record returns the number of records read).

– William Pursell
Jun 3 '13 at 13:38






while( read_structured_record( fp ) == 1 ) { ... would be an idiomatic way to write that (assuming read_structured_record returns the number of records read).

– William Pursell
Jun 3 '13 at 13:38





1




1





File I/O errors may happen anytime, thus by not checking the result of fgetc(fp), one may miss that and not read all the bytes.

– chux
Sep 13 '13 at 17:47





File I/O errors may happen anytime, thus by not checking the result of fgetc(fp), one may miss that and not read all the bytes.

– chux
Sep 13 '13 at 17:47




1




1





Files can grow while you are reading them; they can also shrink. The size given by the one-time stat() operation is not reliable over the long term.

– Jonathan Leffler
Mar 26 '15 at 17:55





Files can grow while you are reading them; they can also shrink. The size given by the one-time stat() operation is not reliable over the long term.

– Jonathan Leffler
Mar 26 '15 at 17:55



Popular posts from this blog

Kamusi Yaliyomo Aina za kamusi | Muundo wa kamusi | Faida za kamusi | Dhima ya picha katika kamusi | Marejeo | Tazama pia | Viungo vya nje | UrambazajiKuhusu kamusiGo-SwahiliWiki-KamusiKamusi ya Kiswahili na Kiingerezakuihariri na kuongeza habari

Swift 4 - func physicsWorld not invoked on collision? The Next CEO of Stack OverflowHow to call Objective-C code from Swift#ifdef replacement in the Swift language@selector() in Swift?#pragma mark in Swift?Swift for loop: for index, element in array?dispatch_after - GCD in Swift?Swift Beta performance: sorting arraysSplit a String into an array in Swift?The use of Swift 3 @objc inference in Swift 4 mode is deprecated?How to optimize UITableViewCell, because my UITableView lags

Access current req object everywhere in Node.js ExpressWhy are global variables considered bad practice? (node.js)Using req & res across functionsHow do I get the path to the current script with Node.js?What is Node.js' Connect, Express and “middleware”?Node.js w/ express error handling in callbackHow to access the GET parameters after “?” in Express?Modify Node.js req object parametersAccess “app” variable inside of ExpressJS/ConnectJS middleware?Node.js Express app - request objectAngular Http Module considered middleware?Session variables in ExpressJSAdd properties to the req object in expressjs with Typescript