5

Given the following C code:

int eofCount = 0;
while (true) {
    int c = fgetc(stdin); 
    if (c == EOF) eofCount++;
}

Will eofCount ever become greater than 1?

I can't find anything in C docs describing what happens with fgetc after EOF has been reached once. I know I can do this book-keeping myself, but if the stdlib does it for me that'd be great.

I'm not looking for code snippets because I've already try this with glibc and in fact eofCount is incremented past EOF. I would like stdlib source code reference or spec that confirms this is the defined behavior. Relying on undefined behavior could lead to problems down the road.

user5534993
  • 518
  • 2
  • 17
Alexandre
  • 5,035
  • 7
  • 29
  • 36
  • It probably does, but it might not be safe to assume. Can you say more about what you're really trying to do? – Guido Mar 17 '17 at 03:23
  • Some basic stream processing. I have my own lib that takes file pointers and does some basic stuff, and I was wondering if the caller of this lib needs to take care to not call it with EOF'd files. I agree that it looks like undefined behavior but I was wondering if someone knows better. – Alexandre Mar 17 '17 at 03:29
  • @Alexandre My answer is downvoted three times but I think that you will find it useful. You will have to click to see it. – Shiv Mar 17 '17 at 03:35
  • Thank you for improving your answer. I have upvoted it. What I'm really looking for is a reference that confirms this, otherwise we might just be using undefined behavior which could cause problems down the line. – Alexandre Mar 17 '17 at 03:41
  • What use does this have? – too honest for this site Mar 17 '17 at 03:41
  • The code itself is useless. It's simply to illustrate the question. The use in the question is not having to track EOF file state. – Alexandre Mar 17 '17 at 03:44
  • @Alexandre compilers overrule the specifications. :) – Shiv Mar 17 '17 at 03:44
  • 1
    You seem not to have searched or read very well. The standard and the POSIX man-page are very clear about the behaviour. – too honest for this site Mar 17 '17 at 03:46
  • @user902384: Only for implementation-defined and undefined behaviour. – too honest for this site Mar 17 '17 at 03:47
  • @Olaf True words. – Shiv Mar 17 '17 at 03:49
  • 1
    [Glibc bug 1190](https://sourceware.org/bugzilla/show_bug.cgi?id=1190) The bug was filed in 2005, although the behaviour is much older than that. Not really a duplicate question but highly relevant answer: http://stackoverflow.com/questions/19889296/how-to-end-scanf-by-entering-only-one-eof/19890073#19890073 And my take on the issue from another similar question: http://stackoverflow.com/questions/32322792/why-multiple-eof-enters-to-end-program/32323262#32323262 – rici Mar 17 '17 at 03:50
  • @Olaf there are times when specification clash and then compiler docs come in picture. Programs run not specifications. – Shiv Mar 17 '17 at 03:51
  • @user902384: In this case, it is not the compiler but the particular implementation of the standard C library, which is *not* the same thing. – rici Mar 17 '17 at 03:55
  • @user902384: There is no "clashing" about behaviour defined by the standard. A compiler not following the standard is not a compliant implementation, thus not a C compiler wrt the standard. Of couse the name "C" is not copyrighted, so there is no legal penalty for calling it "C compiler". Nevertheless it must not call itself "standard compliant". Similar for the **standard C library** implementation. And that's what we are talking about. – too honest for this site Mar 17 '17 at 03:57
  • @Olaf I am talking about different standards clashing in much broader sense. Not one. – Shiv Mar 17 '17 at 03:58
  • 1
    @user902384: Which different standards do you think are involved here?? There is only **one** C standard. And that is very clear about the behaviour. Did you even read it? – too honest for this site Mar 17 '17 at 04:00
  • @Olaf I am sorry that I have gone out of scope of the question. There are quite a few C standards. C89, C99 and C11. Which one you are talking about? GCC has not even implemented threads because of glibc issue. I am referring to https://gcc.gnu.org/wiki/C11Status – Shiv Mar 17 '17 at 04:02
  • @user902384: As far as I know, this was always the standardized behaviour of `fgetc`. But it has never been the actual behaviour of glibc when the stream is a terminal. – rici Mar 17 '17 at 04:03
  • @user902384: C90, 95 and 99 are **not** standard. They have been canceled (read the forewords!) with the release of their successor. Current C standard is ISO9899:2011. And how is that related to threads? If you refer to C11: C11-threads are **optional**. – too honest for this site Mar 17 '17 at 04:04
  • @rici No more arguments. I have managed myself to get a ban from stackoverflow from asking questions. Now I do not want to lose the privilege of answering and commenting as well. – Shiv Mar 17 '17 at 04:05
  • @Olaf last reply on this. Read the status page. Many are not even optional. Please. – Shiv Mar 17 '17 at 04:06
  • @Olaf I am violating my words again. You definitely know the fate of `export` keyword in C++. No compiler with the exception of EDG ever implemented that. – Shiv Mar 17 '17 at 04:10
  • @user902384: I have no idea what you are talking about. 1) C++ is a different, unrelated language. 2) THis is not the place for discussion, less about unrelated subjects. – too honest for this site Mar 17 '17 at 04:14
  • @Olaf yes, you are right. I always forget the objective nature of stackoverflow and end up getting downvotes and bans. – Shiv Mar 17 '17 at 04:16

3 Answers3

7

As long as you're not reading from an interactive Linux terminal (i.e. you do not open a file or pipe stdin from some other file/process), once you read EOF all future reads will also read EOF.

If you are reading from a Linux terminal, pressing the key sequence for EOF (CTRL-D on Linux) will read as EOF but you can still enter in more characters and read them.

From section 7.21.7.1 of the C standard:

3 If the end-of-file indicator for the stream is set, or if the stream is at end-of-file, the end-of-file indicator for the stream is set and the fgetc function returns EOF. Otherwise, the fgetc function returns the next character from the input stream pointed to by stream. If a read error occurs, the error indicator for the stream is set and the fgetc function returns EOF.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
dbush
  • 205,898
  • 23
  • 218
  • 273
  • That's what I imagined but can we find a reference? I'm looking at https://chromium.googlesource.com/chromiumos/third_party/glibc/+/cvs/libc-970216/stdio/fgetc.c and https://chromium.googlesource.com/chromiumos/third_party/glibc/+/cvs/libc-970216/stdio/stdio.h to see if this is well defined in glibc. – Alexandre Mar 17 '17 at 03:39
  • That is confirmed as my programs gives count as one with following input sequence EOF 1 EOF. – Shiv Mar 17 '17 at 03:43
  • 1
    @Alexandre: the C standard *is* a reference :) Another one is in Posix. However, glibc does not properly implement these references for non-file streams. – rici Mar 17 '17 at 03:47
  • 1
    @dbush: Where in that excerpt from the C standard is the exception for terminals? :) – rici Mar 17 '17 at 03:48
  • 1
    If Linux (actually most likely glibc) behaves like this it is not compliant. – too honest for this site Mar 17 '17 at 04:09
  • @rici: POSIX just refers to the C standard for this behaviour. – too honest for this site Mar 17 '17 at 04:10
  • @olaf: I know. But it can be referred to, so it's a reference. Personally I find this glibc bug really annoying but the odds of it being fixed in my lifetime seem very small. – rici Mar 17 '17 at 04:11
  • @rici: I meant that POSIX just references the C standard, thus it is just another indirection. AFIK POSIX must not tell different than the C standard in general. – too honest for this site Mar 17 '17 at 04:13
  • I'm with @Olaf. On a Mac, the EOF indicator gets set, and stays set, unless you use `clearerr(stdin)` to re-enable input. The behaviour described in this answer flies in the face of the C standard — it is not conformant. The quote supports this: _If the end-of-file indicator for the stream is set, …, the `fgetc` function returns EOF._ The only documented way to get the end-of-file indicator unset is via `clearerr()`. I wrote a program and ran it on my Mac and in an Ubuntu 16.04 LTS VM; it behaves completely differently in the two environments. The Mac behaviour is the traditional behaviour. – Jonathan Leffler Mar 17 '17 at 04:38
6

Does fgetc return EOF on every call after end-of-file reached?

It depends of 2 indicators and I/O function calls.


Although not mentioned by OP, there are 2 reasons why fgetc(stdin); returns EOF and how they affect following fgetc() calls is not symmetric. Further, use of various I/O functions affect 2 indicators that in turn affect following fgetc() calls

End-of-file.
Input error.


The C spec is explicit on the end-of-file indicator causing subsequent EOF.

If the end-of-file indicator for the input stream pointed to by stream is not set and a next character is present, the fgetc function obtains that character ... C11 §7.21.7.1 2

When end-of-file occurs or had occurred, a persistent flag is set: end-of-file indicator, so subsequent calls to fgetc() will return EOF.

If the end-of-file indicator for the stream is set, or if the stream is at end-of-file, the end-of-file indicator for the stream is set and the fgetc function returnsEOF ... §7.21.7.1 3


When a rare input error occurs, fgetc() returns EOF, but that event does not set the end-of-file indicator, but an error indicator is set. Subsequent calls do not necessarily return EOF, even though a error indicator is set. IMO, the C spec is insufficiency clear on this point.

If a read error occurs, the error indicator for the stream is set and the fgetc function returns EOF §7.21.7.1 3


A call to feof(), and ferror() can be used to distinguish what caused the EOF, yet also may reflect prior I/O activity. Thus good code promptly checks these functions after an EOF is returned and clears them if following I/O is to occur.


The end-of-file indicator and error indicator can be cleared with void clearerr(FILE *stream);

The rewind() function clears the error indicator.

ungetc() will clear the end-of-file indicator.

Other I/O functions also affect these indicators.


Subsequent calls to fgetc() might not return EOF if the condition the caused the first EOF is removed and corresponding indicator is cleared.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • I don't think the standard is unclear about an error condition. If the read error is encountered, the error flag is set. But a subsequent call might have no error, so it returns the next character. Said that, it is good practice to check for error after `fgetc(...) == EOF`. `feof` should be treated carefully; it's design is … problematic. – too honest for this site Mar 17 '17 at 04:54
-2

Yes the count will become greater than one because you have an infinite while loop. You would find http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf and http://pubs.opengroup.org/onlinepubs/9699919799/ useful.

Try this:

#include <stdio.h>
#include <stdbool.h>

int main() {
    int eofCount = 0;
    /*while (true) {*/

    int c = fgetc(stdin); 
    if (c == EOF) eofCount++;
        c = fgetc(stdin); 
    if (c == EOF) eofCount++;
        c = fgetc(stdin); 
    if (c == EOF) eofCount++;

    /*}*/

printf("%d\n", eofCount);
return 0;

}

Compile and run. Hit ctrl+D twice on Linux and then enter. You will get 2.

This was compiled with gcc -ansi -Wall -Werror -pedantic test.c so it satisfied ANSI i.e. C89 standard.

Shiv
  • 1,912
  • 1
  • 15
  • 21
  • That's not answering the question regarding EOF. The infinete loop is irrelevant if the `if` condition does not evaluate to true each time - which is what the question is really asking. – kaylum Mar 17 '17 at 03:29
  • `Will eofCount ever become greater than 1?` this is _the_ question with "?" – Shiv Mar 17 '17 at 03:30
  • 1
    Read the whole question. Context matters. – kaylum Mar 17 '17 at 03:31
  • @kaylum Sorry for being hasty. I have updated the answer. – Shiv Mar 17 '17 at 03:33