How a stream error indicator affects following input code?











up vote
4
down vote

favorite
1












Each stream has "an error indicator that records whether a read/write error has occurred".



It is set, usually rarely, by various functions: fgetc(), fflush(), fseek(), ....



It is cleared by various functions: rewind(), clearerr(), fopen(), ....



int ferror(FILE *stream) reports the state.




The ferror function returns nonzero if and only if the error indicator is set for stream.






In this case, certainly an input error just occurred.



if (!ferror(istream)) {
int ch = fgetc(istream);
if (ch == EOF && ferror(istream)) {
puts("Input error just occurred");
}
}




Exploring fgetc() deeper, fgetc() does not return EOF because the error indicator was set, but because "If a read error occurs" or end-of-file related reasons1. Usually once an error occurs (e. g. parity error on a serial stream), code does not continue reading without clearing the error, yet consider what happens when it does continue.



I see 8 situations: the error indicator set/clear prior to fgetc(), fgetc() returns EOF or not, and a following ferror() could be true or not.



int e1 = !!ferror(istream);
int eof = fgetc(istream) == EOF;
int e2 = !!ferror(istream);


Assuming no UB, are 5 of the 8 possible and not the 3 unexpected ones? especially is valid input possible with error indicator set? 2



e1 eof e2  
0 0 0 Normal reading of valid data
0 0 1 Unexpected
0 1 0 End-of-file
0 1 1 Input error
1 0 0 Unexpected
1 0 1 Normal reading of valid data with error indicator set!
1 1 0 Unexpected
1 1 1 Input error or end-of-file




With the error indicator set prior to an input operation, things become complicated and clearing it beforehand simplifies code. Yet that prevents error indicator accumulation.



If codes does not clear the error indicator before hand and wants to detect if a line of input had a rare input error, it seems to make sense to test !feof() and not ferror() to detect.



Is checking ferror() potentially misleading? or have I missed something about the error indicator?



char buf[80];
for (int i=0; i<(80-1); i++) {
int ch = fgetc(stdin);
if (ch == EOF) {
if (ferror(stdin)) {
puts("Input error or (Prior input error and end of file occurred)"); // ambiguous
}
if (feof(stdin)) {
puts("End of file occurred");
} else {
puts("Input error occurred"); // ferror() test not needed
i = 0; // ignore prior input
}
break;
}
if (ch == 'n') break;
buf[i++] = ch;
}
buf[i] = 0;




Similar questions



File operations with error indicator set
. This unanswered one centers on accumulating error indicator without testing fgetc() return value (answers venture off into errno and making a user error flag) and this one is trying to simply disambiguate a fgetc().



fgetc(): Is it enough to just check EOF? does not address error indicator set prior to fgetc().



Similar issues apply to output and I/O streams, yet this question focuses on input streams.





1int fgetc(FILE *stream) Returns




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. C11dr §7.21.7.1 2




2 On cases 0-1-0, 1-1-1. Seems if UCHAR_MAX == UINT_MAX, a unsigned char, could be returned and equate to EOF and not be due to end-of-file nor input error.










share|improve this question
























  • Are you looking for a standards-based answer (perhaps language-lawyer), or a practical answer?
    – Nominal Animal
    Nov 13 at 2:08










  • @NominalAnimal Closer to standards-based than only practical as I am trying to divine the error indicator mysteries to solve: when fgetc() returns EOF, is that due to a recent error, end-of-file, some wide unsigned char or something else? LL added.
    – chux
    Nov 13 at 2:16












  • FWIW, with glibc it is always either due to detecting a new end-of-file or error condition, since the fgetc()/getc()/getchar() functions never examine the error flag.
    – Nominal Animal
    Nov 13 at 2:30










  • @NominalAnimal Does glibc also return EOF on existing end-of-file flag and not just a new end-of-file?
    – chux
    Nov 13 at 2:35








  • 1




    The behavior of glibc fgetc was changed in version 2.28, see sourceware.org/ml/libc-alpha/2018-08/msg00003.html and sourceware.org/bugzilla/show_bug.cgi?id=1190 . We sure thought 7.21.7p2,3 mandated "sticky EOF" -- the change is described as "correct[ing] a long-standing C99 conformance bug". (However, the EOF indicator and the error indicator are two separate bits.)
    – zwol
    Nov 14 at 17:35

















up vote
4
down vote

favorite
1












Each stream has "an error indicator that records whether a read/write error has occurred".



It is set, usually rarely, by various functions: fgetc(), fflush(), fseek(), ....



It is cleared by various functions: rewind(), clearerr(), fopen(), ....



int ferror(FILE *stream) reports the state.




The ferror function returns nonzero if and only if the error indicator is set for stream.






In this case, certainly an input error just occurred.



if (!ferror(istream)) {
int ch = fgetc(istream);
if (ch == EOF && ferror(istream)) {
puts("Input error just occurred");
}
}




Exploring fgetc() deeper, fgetc() does not return EOF because the error indicator was set, but because "If a read error occurs" or end-of-file related reasons1. Usually once an error occurs (e. g. parity error on a serial stream), code does not continue reading without clearing the error, yet consider what happens when it does continue.



I see 8 situations: the error indicator set/clear prior to fgetc(), fgetc() returns EOF or not, and a following ferror() could be true or not.



int e1 = !!ferror(istream);
int eof = fgetc(istream) == EOF;
int e2 = !!ferror(istream);


Assuming no UB, are 5 of the 8 possible and not the 3 unexpected ones? especially is valid input possible with error indicator set? 2



e1 eof e2  
0 0 0 Normal reading of valid data
0 0 1 Unexpected
0 1 0 End-of-file
0 1 1 Input error
1 0 0 Unexpected
1 0 1 Normal reading of valid data with error indicator set!
1 1 0 Unexpected
1 1 1 Input error or end-of-file




With the error indicator set prior to an input operation, things become complicated and clearing it beforehand simplifies code. Yet that prevents error indicator accumulation.



If codes does not clear the error indicator before hand and wants to detect if a line of input had a rare input error, it seems to make sense to test !feof() and not ferror() to detect.



Is checking ferror() potentially misleading? or have I missed something about the error indicator?



char buf[80];
for (int i=0; i<(80-1); i++) {
int ch = fgetc(stdin);
if (ch == EOF) {
if (ferror(stdin)) {
puts("Input error or (Prior input error and end of file occurred)"); // ambiguous
}
if (feof(stdin)) {
puts("End of file occurred");
} else {
puts("Input error occurred"); // ferror() test not needed
i = 0; // ignore prior input
}
break;
}
if (ch == 'n') break;
buf[i++] = ch;
}
buf[i] = 0;




Similar questions



File operations with error indicator set
. This unanswered one centers on accumulating error indicator without testing fgetc() return value (answers venture off into errno and making a user error flag) and this one is trying to simply disambiguate a fgetc().



fgetc(): Is it enough to just check EOF? does not address error indicator set prior to fgetc().



Similar issues apply to output and I/O streams, yet this question focuses on input streams.





1int fgetc(FILE *stream) Returns




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. C11dr §7.21.7.1 2




2 On cases 0-1-0, 1-1-1. Seems if UCHAR_MAX == UINT_MAX, a unsigned char, could be returned and equate to EOF and not be due to end-of-file nor input error.










share|improve this question
























  • Are you looking for a standards-based answer (perhaps language-lawyer), or a practical answer?
    – Nominal Animal
    Nov 13 at 2:08










  • @NominalAnimal Closer to standards-based than only practical as I am trying to divine the error indicator mysteries to solve: when fgetc() returns EOF, is that due to a recent error, end-of-file, some wide unsigned char or something else? LL added.
    – chux
    Nov 13 at 2:16












  • FWIW, with glibc it is always either due to detecting a new end-of-file or error condition, since the fgetc()/getc()/getchar() functions never examine the error flag.
    – Nominal Animal
    Nov 13 at 2:30










  • @NominalAnimal Does glibc also return EOF on existing end-of-file flag and not just a new end-of-file?
    – chux
    Nov 13 at 2:35








  • 1




    The behavior of glibc fgetc was changed in version 2.28, see sourceware.org/ml/libc-alpha/2018-08/msg00003.html and sourceware.org/bugzilla/show_bug.cgi?id=1190 . We sure thought 7.21.7p2,3 mandated "sticky EOF" -- the change is described as "correct[ing] a long-standing C99 conformance bug". (However, the EOF indicator and the error indicator are two separate bits.)
    – zwol
    Nov 14 at 17:35















up vote
4
down vote

favorite
1









up vote
4
down vote

favorite
1






1





Each stream has "an error indicator that records whether a read/write error has occurred".



It is set, usually rarely, by various functions: fgetc(), fflush(), fseek(), ....



It is cleared by various functions: rewind(), clearerr(), fopen(), ....



int ferror(FILE *stream) reports the state.




The ferror function returns nonzero if and only if the error indicator is set for stream.






In this case, certainly an input error just occurred.



if (!ferror(istream)) {
int ch = fgetc(istream);
if (ch == EOF && ferror(istream)) {
puts("Input error just occurred");
}
}




Exploring fgetc() deeper, fgetc() does not return EOF because the error indicator was set, but because "If a read error occurs" or end-of-file related reasons1. Usually once an error occurs (e. g. parity error on a serial stream), code does not continue reading without clearing the error, yet consider what happens when it does continue.



I see 8 situations: the error indicator set/clear prior to fgetc(), fgetc() returns EOF or not, and a following ferror() could be true or not.



int e1 = !!ferror(istream);
int eof = fgetc(istream) == EOF;
int e2 = !!ferror(istream);


Assuming no UB, are 5 of the 8 possible and not the 3 unexpected ones? especially is valid input possible with error indicator set? 2



e1 eof e2  
0 0 0 Normal reading of valid data
0 0 1 Unexpected
0 1 0 End-of-file
0 1 1 Input error
1 0 0 Unexpected
1 0 1 Normal reading of valid data with error indicator set!
1 1 0 Unexpected
1 1 1 Input error or end-of-file




With the error indicator set prior to an input operation, things become complicated and clearing it beforehand simplifies code. Yet that prevents error indicator accumulation.



If codes does not clear the error indicator before hand and wants to detect if a line of input had a rare input error, it seems to make sense to test !feof() and not ferror() to detect.



Is checking ferror() potentially misleading? or have I missed something about the error indicator?



char buf[80];
for (int i=0; i<(80-1); i++) {
int ch = fgetc(stdin);
if (ch == EOF) {
if (ferror(stdin)) {
puts("Input error or (Prior input error and end of file occurred)"); // ambiguous
}
if (feof(stdin)) {
puts("End of file occurred");
} else {
puts("Input error occurred"); // ferror() test not needed
i = 0; // ignore prior input
}
break;
}
if (ch == 'n') break;
buf[i++] = ch;
}
buf[i] = 0;




Similar questions



File operations with error indicator set
. This unanswered one centers on accumulating error indicator without testing fgetc() return value (answers venture off into errno and making a user error flag) and this one is trying to simply disambiguate a fgetc().



fgetc(): Is it enough to just check EOF? does not address error indicator set prior to fgetc().



Similar issues apply to output and I/O streams, yet this question focuses on input streams.





1int fgetc(FILE *stream) Returns




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. C11dr §7.21.7.1 2




2 On cases 0-1-0, 1-1-1. Seems if UCHAR_MAX == UINT_MAX, a unsigned char, could be returned and equate to EOF and not be due to end-of-file nor input error.










share|improve this question















Each stream has "an error indicator that records whether a read/write error has occurred".



It is set, usually rarely, by various functions: fgetc(), fflush(), fseek(), ....



It is cleared by various functions: rewind(), clearerr(), fopen(), ....



int ferror(FILE *stream) reports the state.




The ferror function returns nonzero if and only if the error indicator is set for stream.






In this case, certainly an input error just occurred.



if (!ferror(istream)) {
int ch = fgetc(istream);
if (ch == EOF && ferror(istream)) {
puts("Input error just occurred");
}
}




Exploring fgetc() deeper, fgetc() does not return EOF because the error indicator was set, but because "If a read error occurs" or end-of-file related reasons1. Usually once an error occurs (e. g. parity error on a serial stream), code does not continue reading without clearing the error, yet consider what happens when it does continue.



I see 8 situations: the error indicator set/clear prior to fgetc(), fgetc() returns EOF or not, and a following ferror() could be true or not.



int e1 = !!ferror(istream);
int eof = fgetc(istream) == EOF;
int e2 = !!ferror(istream);


Assuming no UB, are 5 of the 8 possible and not the 3 unexpected ones? especially is valid input possible with error indicator set? 2



e1 eof e2  
0 0 0 Normal reading of valid data
0 0 1 Unexpected
0 1 0 End-of-file
0 1 1 Input error
1 0 0 Unexpected
1 0 1 Normal reading of valid data with error indicator set!
1 1 0 Unexpected
1 1 1 Input error or end-of-file




With the error indicator set prior to an input operation, things become complicated and clearing it beforehand simplifies code. Yet that prevents error indicator accumulation.



If codes does not clear the error indicator before hand and wants to detect if a line of input had a rare input error, it seems to make sense to test !feof() and not ferror() to detect.



Is checking ferror() potentially misleading? or have I missed something about the error indicator?



char buf[80];
for (int i=0; i<(80-1); i++) {
int ch = fgetc(stdin);
if (ch == EOF) {
if (ferror(stdin)) {
puts("Input error or (Prior input error and end of file occurred)"); // ambiguous
}
if (feof(stdin)) {
puts("End of file occurred");
} else {
puts("Input error occurred"); // ferror() test not needed
i = 0; // ignore prior input
}
break;
}
if (ch == 'n') break;
buf[i++] = ch;
}
buf[i] = 0;




Similar questions



File operations with error indicator set
. This unanswered one centers on accumulating error indicator without testing fgetc() return value (answers venture off into errno and making a user error flag) and this one is trying to simply disambiguate a fgetc().



fgetc(): Is it enough to just check EOF? does not address error indicator set prior to fgetc().



Similar issues apply to output and I/O streams, yet this question focuses on input streams.





1int fgetc(FILE *stream) Returns




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. C11dr §7.21.7.1 2




2 On cases 0-1-0, 1-1-1. Seems if UCHAR_MAX == UINT_MAX, a unsigned char, could be returned and equate to EOF and not be due to end-of-file nor input error.







c error-handling language-lawyer






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 13 at 2:16

























asked Nov 13 at 1:53









chux

78.5k869144




78.5k869144












  • Are you looking for a standards-based answer (perhaps language-lawyer), or a practical answer?
    – Nominal Animal
    Nov 13 at 2:08










  • @NominalAnimal Closer to standards-based than only practical as I am trying to divine the error indicator mysteries to solve: when fgetc() returns EOF, is that due to a recent error, end-of-file, some wide unsigned char or something else? LL added.
    – chux
    Nov 13 at 2:16












  • FWIW, with glibc it is always either due to detecting a new end-of-file or error condition, since the fgetc()/getc()/getchar() functions never examine the error flag.
    – Nominal Animal
    Nov 13 at 2:30










  • @NominalAnimal Does glibc also return EOF on existing end-of-file flag and not just a new end-of-file?
    – chux
    Nov 13 at 2:35








  • 1




    The behavior of glibc fgetc was changed in version 2.28, see sourceware.org/ml/libc-alpha/2018-08/msg00003.html and sourceware.org/bugzilla/show_bug.cgi?id=1190 . We sure thought 7.21.7p2,3 mandated "sticky EOF" -- the change is described as "correct[ing] a long-standing C99 conformance bug". (However, the EOF indicator and the error indicator are two separate bits.)
    – zwol
    Nov 14 at 17:35




















  • Are you looking for a standards-based answer (perhaps language-lawyer), or a practical answer?
    – Nominal Animal
    Nov 13 at 2:08










  • @NominalAnimal Closer to standards-based than only practical as I am trying to divine the error indicator mysteries to solve: when fgetc() returns EOF, is that due to a recent error, end-of-file, some wide unsigned char or something else? LL added.
    – chux
    Nov 13 at 2:16












  • FWIW, with glibc it is always either due to detecting a new end-of-file or error condition, since the fgetc()/getc()/getchar() functions never examine the error flag.
    – Nominal Animal
    Nov 13 at 2:30










  • @NominalAnimal Does glibc also return EOF on existing end-of-file flag and not just a new end-of-file?
    – chux
    Nov 13 at 2:35








  • 1




    The behavior of glibc fgetc was changed in version 2.28, see sourceware.org/ml/libc-alpha/2018-08/msg00003.html and sourceware.org/bugzilla/show_bug.cgi?id=1190 . We sure thought 7.21.7p2,3 mandated "sticky EOF" -- the change is described as "correct[ing] a long-standing C99 conformance bug". (However, the EOF indicator and the error indicator are two separate bits.)
    – zwol
    Nov 14 at 17:35


















Are you looking for a standards-based answer (perhaps language-lawyer), or a practical answer?
– Nominal Animal
Nov 13 at 2:08




Are you looking for a standards-based answer (perhaps language-lawyer), or a practical answer?
– Nominal Animal
Nov 13 at 2:08












@NominalAnimal Closer to standards-based than only practical as I am trying to divine the error indicator mysteries to solve: when fgetc() returns EOF, is that due to a recent error, end-of-file, some wide unsigned char or something else? LL added.
– chux
Nov 13 at 2:16






@NominalAnimal Closer to standards-based than only practical as I am trying to divine the error indicator mysteries to solve: when fgetc() returns EOF, is that due to a recent error, end-of-file, some wide unsigned char or something else? LL added.
– chux
Nov 13 at 2:16














FWIW, with glibc it is always either due to detecting a new end-of-file or error condition, since the fgetc()/getc()/getchar() functions never examine the error flag.
– Nominal Animal
Nov 13 at 2:30




FWIW, with glibc it is always either due to detecting a new end-of-file or error condition, since the fgetc()/getc()/getchar() functions never examine the error flag.
– Nominal Animal
Nov 13 at 2:30












@NominalAnimal Does glibc also return EOF on existing end-of-file flag and not just a new end-of-file?
– chux
Nov 13 at 2:35






@NominalAnimal Does glibc also return EOF on existing end-of-file flag and not just a new end-of-file?
– chux
Nov 13 at 2:35






1




1




The behavior of glibc fgetc was changed in version 2.28, see sourceware.org/ml/libc-alpha/2018-08/msg00003.html and sourceware.org/bugzilla/show_bug.cgi?id=1190 . We sure thought 7.21.7p2,3 mandated "sticky EOF" -- the change is described as "correct[ing] a long-standing C99 conformance bug". (However, the EOF indicator and the error indicator are two separate bits.)
– zwol
Nov 14 at 17:35






The behavior of glibc fgetc was changed in version 2.28, see sourceware.org/ml/libc-alpha/2018-08/msg00003.html and sourceware.org/bugzilla/show_bug.cgi?id=1190 . We sure thought 7.21.7p2,3 mandated "sticky EOF" -- the change is described as "correct[ing] a long-standing C99 conformance bug". (However, the EOF indicator and the error indicator are two separate bits.)
– zwol
Nov 14 at 17:35














4 Answers
4






active

oldest

votes

















up vote
2
down vote



accepted











Assuming no UB, are 5 of the 8 possible and not the 3 unexpected ones?
especially is valid input possible with error indicator set?




Speaking specifically to the provisions of the standard, I'm inclined to agree with your analysis:





  • Few functions are specified to clear the error indicator of a stream, and fgetc() is not one of them. More generally, none of them are data-transfer functions. Therefore, if the error indicator is set for a stream before that stream is presented to fgetc() for reading, then it should still be set when that function returns, all other considerations notwithstanding. That covers these cases:*



    1  0   0   Unexpected
    1 1 0 Unexpected
    1 1 1 Input error or end-of-file


    It also covers this case with respect to the expected value of the error indicator, though it does not speak to whether it can actually happen:



    1  0   1   Normal reading of valid data with error indicator set!



  • fgetc() is specified to return EOF in every situation in which it is specified to set the end-of-file indicator on a stream. Therefore, if fgetc() returns anything other than EOF then it will not, on that call, have set the stream's error (or end-of-file) indicator. That covers these cases:



    0  0   0   Normal reading of valid data    
    0 0 1 Unexpected


    On the other hand, if fgetc() does return EOF then either the stream's end-of-file indicator or its error indicator should afterward be found set. But the standard distinguishes between these cases, and specifies that the user can distinguish them via the feof() and ferror() functions. That covers these cases:*



    0  1   0   End-of-file
    0 1 1 Input error



  • Finally, I concur that none of the behavior of fgetc() is conditioned on the initial state of the stream's error indicator. Provided only that the stream is not initially positioned at its end, and its end-of-file indicator is not initially set, "the fgetc function returns the next character from the input stream pointed to by stream." That establishes that this, the case of most interest, is in fact allowed:



    1  0   1   Normal reading of valid data with error indicator set!


    However, that the case is allowed in the abstract does not imply that it can be observed in practice. The details seem unspecified, and I would expect them to depend on the implementation of the driver serving the stream in question. It is entirely possible that having once encountered an error, the driver will continue to report an error on subsequent reads until reset appropriately, and perhaps longer. From the C perspective, that would be interpreted as an (additional) error occurring on each subsequent read, and nothing in the language specifications prevents that. Not even use of one of the functions that clear a stream's error indicator.





If codes does not clear the error indicator before hand and wants to
detect if a line of input had a rare input error, it seems to make
sense to test !feof() and not ferror() to detect.



Is checking ferror() potentially misleading? or have I missed something about the error indicator?




I agree that if a stream's error indicator is initially set, its end-of-file indicator is not, and reading it with fgetc() returns EOF, then ferror() does not usefully distinguish between the end-of-file and error cases whereas feof() should.



On the other hand, whether one can usefully continue to read a given stream after an error has been encountered on it depends on implementation and possibly on specific circumstances. That applies even if the error indicator is cleared via a clearerr() call, not to mention if the error indicator is not cleared.





* Although I agree that there is an ambiguity with respect to EOF in the event that UCHAR_MAX > INT_MAX, I assert that that is just one of several reasons why such an implementation would be problematic. As a practical matter, therefore, I disregard such implementations as entirely hypothetical.






share|improve this answer























  • Additional interest in "usefully continue to read a given stream after an error has been encountered" comes from reviewing input functions for robustness. Example: my_getline(). Such functions, when called, may or may not have the error indicator set. It is outside the function's control to prevent being called when a prior error had been encountered - just like fgetc(). Detection of input error seems to better rely on c == EOF && !feof(stdin) than c == EOF && ferror(...), so I was seeking other good ideas concerning input error.
    – chux
    Nov 14 at 11:33








  • 1




    @chux, I agree that having performed int c = fgetc(s); in a conforming C implementation, without knowledge of the initial state of stream s, testing for an error on that read via c == EOF && !feof(s) is valid, and it is more reliable than its analog involving ferror. If ferror is to be used instead, then the stream's error indicator must first be ensured clear. I am unaware of any alternatives fundamentally different from these.
    – John Bollinger
    Nov 14 at 14:14


















up vote
1
down vote













Everything you say seems right, and ch==EOF && !feof(f) is the right way to check for new errors without interfering with error accumulation.






share|improve this answer




























    up vote
    1
    down vote













    Here is a very crude, very minimal program to explore the behaviour of GNU C library with respect to fgetc(), ferror(), and feof(), as requested by OP in a comment:



    #define  _POSIX_C_SOURCE  200809L
    #include <stdlib.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <string.h>
    #include <signal.h>
    #include <errno.h>

    static volatile sig_atomic_t interrupted = 0;

    static void interrupt_handler(int signum)
    {
    interrupted = 1;
    }

    static int install_interrupt(const int signum)
    {
    struct sigaction act;

    memset(&act, 0, sizeof act);
    sigemptyset(&act.sa_mask);
    act.sa_handler = interrupt_handler;
    act.sa_flags = 0;
    if (sigaction(signum, &act, NULL) == -1)
    return -1;

    return 0;
    }

    int main(void)
    {
    int n, c;

    if (install_interrupt(SIGALRM)) {
    fprintf(stderr, "Cannot install SIGALRM handler: %s.n", strerror(errno));
    return EXIT_FAILURE;
    }

    if (ferror(stdin)) {
    fprintf(stderr, "Standard input is already in error state.n");
    return EXIT_FAILURE;
    }
    if (feof(stdin)) {
    fprintf(stderr, "Standard input is already in end-of-input state.n");
    return EXIT_FAILURE;
    }

    fprintf(stderr, "Testing stream error state. Please wait.n");

    alarm(1);
    c = fgetc(stdin);
    if (c != EOF) {
    fprintf(stderr, "Stream error state test failed.n");
    return EXIT_FAILURE;
    }

    fprintf(stderr, "fgetc(stdin) returned EOF.n");
    fprintf(stderr, "ferror(stdin) returns %d.n", ferror(stdin));
    fprintf(stderr, "feof(stdin) returns %d.n", feof(stdin));

    fprintf(stderr, "n");
    fprintf(stderr, "Testing stream end-of-input state. Please press Ctrl+D.n");
    c = fgetc(stdin);
    if (c != EOF) {
    fprintf(stderr, "fgetc() returned %d; EOF was expected.n", c);
    return EXIT_FAILURE;
    }
    fprintf(stderr, "fgetc(stdin) returned EOF.n");
    fprintf(stderr, "ferror(stdin) returns %d.n", ferror(stdin));
    fprintf(stderr, "feof(stdin) returns %d.n", feof(stdin));
    if (!ferror(stdin) || !feof(stdin)) {
    fprintf(stderr, "Expected error and end-of-file states; aborting.n");
    return EXIT_FAILURE;
    }

    fprintf(stderr, "n");
    fprintf(stderr, "Testing fgetc() when stream in error and end-of-file state.n");
    fprintf(stderr, "Please type something, then press Enter.n");
    n = 0;
    c = fgetc(stdin);
    while (c != EOF && c != 'n') {
    n++;
    c = fgetc(stdin);
    }
    if (c == EOF) {
    fprintf(stderr, "Further input is not possible.n");
    return EXIT_FAILURE;
    } else
    fprintf(stderr, "Further input is possible: %d characters (including Enter) read.n", n + 1);

    return EXIT_SUCCESS;
    }


    When I compile and run the above on Linux, the program will output



    Testing stream error state. Please wait.
    fgetc(stdin) returned EOF.
    ferror(stdin) returns 1.
    feof(stdin) returns 0.


    The error state was caused by having signal delivery interrupt an fgetc(stdin) call. As you can see, it does cause ferror(stdin) to return nonzero. Note that feof(stdin) returns 0, though.



    The output continues:



    Testing stream end-of-input state. Please press Ctrl+D.


    Pressing Ctrl+C yields output



    fgetc(stdin) returned EOF.
    ferror(stdin) returns 1.
    feof(stdin) returns 1.


    At this point, the standard input is in both error and end-of-file states. The output continues:



    Testing fgetc() when stream in error and end-of-file state.
    Please type something, then press Enter.


    If we now type say O K Enter, we get



    Further input is possible: 3 characters (including Enter) read.


    This proves that at least the GNU C library implementation does not check the stream error or end-of-file status at all. It will simply try to read more data (using the underlying read() operation in POSIXy systems).






    share|improve this answer





















    • I also found similar results, yet tend to think it is non-conforming to the standard. (IOWs, a bug in that version). I also noticed that the end-of-file flag was cleared by fgetc() call with 5 key "xn", Ctrl d, ".n" sequence with the '.' key.
      – chux
      Nov 14 at 18:57












    • @chux: On POSIXy systems, the EOF behaviour kinda makes sense, because if the file gets appended to after we read it till the end, we'll want to get the appended data; and since there is no cleareof() function, reopening the file would be the only way to do that otherwise. Whether any of this is standards-conformant, I have no opinion: I've decided to steer away from language-lawyer. (If it is a bug in glibc, getting it fixed is a quixotic fight against people who believe they know the standards better than anyone else. Not worth the effort, IMO.)
      – Nominal Animal
      Nov 14 at 19:09










    • Re: "there is no cleareof()". Would not clearerr(istream) be sufficient in lieu of reopening the file? IAC, thanks for the exploring the corners of C I/O.
      – chux
      Nov 14 at 19:14












    • @NominalAnimal For the record, if you believe you have found a bug in glibc and you don't feel like arguing with Joseph and/or Paul Eggert about it, you can email me and I'll do it. Ulrich is no longer involved.
      – zwol
      Nov 14 at 19:27












    • @zwol: Yeah, libio/getc.c:_IO_getc() and libio/getc_u.c:__getc_unlocked() are still missing an _IO_ferror_unlocked() check in HEAD. I'd recommend turning _IO_getc_unlocked() into a function that does the check, and returns __getc_unlocked_body(). Also, an RFC to the devs: perhaps change _IO_EOF_SEEN in libio/bits/types/struct_FILE.h to 0x0030, so that feof() returns nonzero if eof or error.
      – Nominal Animal
      Nov 14 at 20:58




















    up vote
    0
    down vote













    My reading of the standard is that it doesn't explicitly say fgetc is allowed to return a non-EOF value if the error indicator was already set on the stream on entry, but it doesn't explicitly say that it can't, either. I sympathize with Nominal Animal's observation (which I shall hoist from comments on his answer in case it gets deleted or moved to chat; allow me to grind my personal axe for a moment and observe that the policy of treating comments as "ephemeral" is harmful and should be abolished):




    IMHO the standard is then bass-ackwards: there is no practical need for EOF to be sticky, but if error is not sticky, then there is a real risk of accidentally missing errors.




    However, if existing implementations are all consistently not treating error as sticky, changing the behavior will be very hard to sell to the committee. Therefore, I am soliciting tests from the community:



    Below is a shortened, non-interactive version of Nominal Animal's test program. It only looks at the behavior of fgetc after a read error, not after EOF. It uses SIGALRM to interrupt a read, instead of control-C, so you don't have to do anything but run it.



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

    static _Noreturn void
    perror_exit (const char *msg)
    {
    perror (msg);
    exit (1);
    }

    static void
    handler (int unused)
    {
    }

    int
    main (void)
    {
    struct sigaction sa;
    int pipefd[2];
    FILE *fp;
    int ch, pa;

    setvbuf (stdout, 0, _IOLBF, 0);

    sa.sa_handler = handler;
    sa.sa_flags = 0; /* DO interrupt blocking system calls */
    sigemptyset (&sa.sa_mask);
    if (sigaction (SIGALRM, &sa, 0))
    perror_exit ("sigaction");

    if (pipe (pipefd))
    perror_exit ("pipe");

    fp = fdopen (pipefd[0], "r");
    if (!fp)
    perror_exit ("fdopen");

    printf ("before fgetc 1, feof = %d ferror = %dn",
    feof (fp), ferror (fp));

    alarm (1);
    ch = fgetc (fp);

    if (ch == EOF)
    printf ("after fgetc 1, ch = EOF feof = %d ferror = %dn",
    feof (fp), ferror (fp));
    else
    printf ("after fgetc 1, ch = '%c' feof = %d ferror = %dn",
    ch, feof (fp), ferror (fp));

    write (pipefd[1], "x", 1);
    alarm (1);
    ch = fgetc (fp);
    pa = alarm (0);

    printf ("after fgetc 2, alarm %sn",
    pa ? "did not fire" : "fired");

    if (ch == EOF)
    printf ("after fgetc 2, ch = EOF feof = %d ferror = %dn",
    feof (fp), ferror (fp));
    else
    printf ("after fgetc 2, ch = '%c' feof = %d ferror = %dn",
    ch, feof (fp), ferror (fp));

    return 0;
    }


    On all three of Linux with glibc 2.27, NetBSD 7.1.2, and FreeBSD 11.2-RELEASE-p4 (which is all of the Unixes I can get at at the moment), this program prints



    before fgetc 1, feof = 0 ferror = 0
    after fgetc 1, ch = EOF feof = 0 ferror = 1
    after fgetc 2, alarm did not fire
    after fgetc 2, ch = 'x' feof = 0 ferror = 1


    consistent with John Bollinger's observation that




    the case of most interest, is in fact allowed:



    1  0   1   Normal reading of valid data with error indicator set!



    I would particularly like to know what this program prints when run on alternative Linux-based C libraries (e.g. musl, bionic); Unixes which are not Linux nor are they BSD-phylum; and Windows. If you've got anything even more exotic please try that too. I'm marking this post community wiki; please edit it to add test results.






    share|improve this answer























      Your Answer






      StackExchange.ifUsing("editor", function () {
      StackExchange.using("externalEditor", function () {
      StackExchange.using("snippets", function () {
      StackExchange.snippets.init();
      });
      });
      }, "code-snippets");

      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "1"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














       

      draft saved


      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53272650%2fhow-a-stream-error-indicator-affects-following-input-code%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      4 Answers
      4






      active

      oldest

      votes








      4 Answers
      4






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes








      up vote
      2
      down vote



      accepted











      Assuming no UB, are 5 of the 8 possible and not the 3 unexpected ones?
      especially is valid input possible with error indicator set?




      Speaking specifically to the provisions of the standard, I'm inclined to agree with your analysis:





      • Few functions are specified to clear the error indicator of a stream, and fgetc() is not one of them. More generally, none of them are data-transfer functions. Therefore, if the error indicator is set for a stream before that stream is presented to fgetc() for reading, then it should still be set when that function returns, all other considerations notwithstanding. That covers these cases:*



        1  0   0   Unexpected
        1 1 0 Unexpected
        1 1 1 Input error or end-of-file


        It also covers this case with respect to the expected value of the error indicator, though it does not speak to whether it can actually happen:



        1  0   1   Normal reading of valid data with error indicator set!



      • fgetc() is specified to return EOF in every situation in which it is specified to set the end-of-file indicator on a stream. Therefore, if fgetc() returns anything other than EOF then it will not, on that call, have set the stream's error (or end-of-file) indicator. That covers these cases:



        0  0   0   Normal reading of valid data    
        0 0 1 Unexpected


        On the other hand, if fgetc() does return EOF then either the stream's end-of-file indicator or its error indicator should afterward be found set. But the standard distinguishes between these cases, and specifies that the user can distinguish them via the feof() and ferror() functions. That covers these cases:*



        0  1   0   End-of-file
        0 1 1 Input error



      • Finally, I concur that none of the behavior of fgetc() is conditioned on the initial state of the stream's error indicator. Provided only that the stream is not initially positioned at its end, and its end-of-file indicator is not initially set, "the fgetc function returns the next character from the input stream pointed to by stream." That establishes that this, the case of most interest, is in fact allowed:



        1  0   1   Normal reading of valid data with error indicator set!


        However, that the case is allowed in the abstract does not imply that it can be observed in practice. The details seem unspecified, and I would expect them to depend on the implementation of the driver serving the stream in question. It is entirely possible that having once encountered an error, the driver will continue to report an error on subsequent reads until reset appropriately, and perhaps longer. From the C perspective, that would be interpreted as an (additional) error occurring on each subsequent read, and nothing in the language specifications prevents that. Not even use of one of the functions that clear a stream's error indicator.





      If codes does not clear the error indicator before hand and wants to
      detect if a line of input had a rare input error, it seems to make
      sense to test !feof() and not ferror() to detect.



      Is checking ferror() potentially misleading? or have I missed something about the error indicator?




      I agree that if a stream's error indicator is initially set, its end-of-file indicator is not, and reading it with fgetc() returns EOF, then ferror() does not usefully distinguish between the end-of-file and error cases whereas feof() should.



      On the other hand, whether one can usefully continue to read a given stream after an error has been encountered on it depends on implementation and possibly on specific circumstances. That applies even if the error indicator is cleared via a clearerr() call, not to mention if the error indicator is not cleared.





      * Although I agree that there is an ambiguity with respect to EOF in the event that UCHAR_MAX > INT_MAX, I assert that that is just one of several reasons why such an implementation would be problematic. As a practical matter, therefore, I disregard such implementations as entirely hypothetical.






      share|improve this answer























      • Additional interest in "usefully continue to read a given stream after an error has been encountered" comes from reviewing input functions for robustness. Example: my_getline(). Such functions, when called, may or may not have the error indicator set. It is outside the function's control to prevent being called when a prior error had been encountered - just like fgetc(). Detection of input error seems to better rely on c == EOF && !feof(stdin) than c == EOF && ferror(...), so I was seeking other good ideas concerning input error.
        – chux
        Nov 14 at 11:33








      • 1




        @chux, I agree that having performed int c = fgetc(s); in a conforming C implementation, without knowledge of the initial state of stream s, testing for an error on that read via c == EOF && !feof(s) is valid, and it is more reliable than its analog involving ferror. If ferror is to be used instead, then the stream's error indicator must first be ensured clear. I am unaware of any alternatives fundamentally different from these.
        – John Bollinger
        Nov 14 at 14:14















      up vote
      2
      down vote



      accepted











      Assuming no UB, are 5 of the 8 possible and not the 3 unexpected ones?
      especially is valid input possible with error indicator set?




      Speaking specifically to the provisions of the standard, I'm inclined to agree with your analysis:





      • Few functions are specified to clear the error indicator of a stream, and fgetc() is not one of them. More generally, none of them are data-transfer functions. Therefore, if the error indicator is set for a stream before that stream is presented to fgetc() for reading, then it should still be set when that function returns, all other considerations notwithstanding. That covers these cases:*



        1  0   0   Unexpected
        1 1 0 Unexpected
        1 1 1 Input error or end-of-file


        It also covers this case with respect to the expected value of the error indicator, though it does not speak to whether it can actually happen:



        1  0   1   Normal reading of valid data with error indicator set!



      • fgetc() is specified to return EOF in every situation in which it is specified to set the end-of-file indicator on a stream. Therefore, if fgetc() returns anything other than EOF then it will not, on that call, have set the stream's error (or end-of-file) indicator. That covers these cases:



        0  0   0   Normal reading of valid data    
        0 0 1 Unexpected


        On the other hand, if fgetc() does return EOF then either the stream's end-of-file indicator or its error indicator should afterward be found set. But the standard distinguishes between these cases, and specifies that the user can distinguish them via the feof() and ferror() functions. That covers these cases:*



        0  1   0   End-of-file
        0 1 1 Input error



      • Finally, I concur that none of the behavior of fgetc() is conditioned on the initial state of the stream's error indicator. Provided only that the stream is not initially positioned at its end, and its end-of-file indicator is not initially set, "the fgetc function returns the next character from the input stream pointed to by stream." That establishes that this, the case of most interest, is in fact allowed:



        1  0   1   Normal reading of valid data with error indicator set!


        However, that the case is allowed in the abstract does not imply that it can be observed in practice. The details seem unspecified, and I would expect them to depend on the implementation of the driver serving the stream in question. It is entirely possible that having once encountered an error, the driver will continue to report an error on subsequent reads until reset appropriately, and perhaps longer. From the C perspective, that would be interpreted as an (additional) error occurring on each subsequent read, and nothing in the language specifications prevents that. Not even use of one of the functions that clear a stream's error indicator.





      If codes does not clear the error indicator before hand and wants to
      detect if a line of input had a rare input error, it seems to make
      sense to test !feof() and not ferror() to detect.



      Is checking ferror() potentially misleading? or have I missed something about the error indicator?




      I agree that if a stream's error indicator is initially set, its end-of-file indicator is not, and reading it with fgetc() returns EOF, then ferror() does not usefully distinguish between the end-of-file and error cases whereas feof() should.



      On the other hand, whether one can usefully continue to read a given stream after an error has been encountered on it depends on implementation and possibly on specific circumstances. That applies even if the error indicator is cleared via a clearerr() call, not to mention if the error indicator is not cleared.





      * Although I agree that there is an ambiguity with respect to EOF in the event that UCHAR_MAX > INT_MAX, I assert that that is just one of several reasons why such an implementation would be problematic. As a practical matter, therefore, I disregard such implementations as entirely hypothetical.






      share|improve this answer























      • Additional interest in "usefully continue to read a given stream after an error has been encountered" comes from reviewing input functions for robustness. Example: my_getline(). Such functions, when called, may or may not have the error indicator set. It is outside the function's control to prevent being called when a prior error had been encountered - just like fgetc(). Detection of input error seems to better rely on c == EOF && !feof(stdin) than c == EOF && ferror(...), so I was seeking other good ideas concerning input error.
        – chux
        Nov 14 at 11:33








      • 1




        @chux, I agree that having performed int c = fgetc(s); in a conforming C implementation, without knowledge of the initial state of stream s, testing for an error on that read via c == EOF && !feof(s) is valid, and it is more reliable than its analog involving ferror. If ferror is to be used instead, then the stream's error indicator must first be ensured clear. I am unaware of any alternatives fundamentally different from these.
        – John Bollinger
        Nov 14 at 14:14













      up vote
      2
      down vote



      accepted







      up vote
      2
      down vote



      accepted







      Assuming no UB, are 5 of the 8 possible and not the 3 unexpected ones?
      especially is valid input possible with error indicator set?




      Speaking specifically to the provisions of the standard, I'm inclined to agree with your analysis:





      • Few functions are specified to clear the error indicator of a stream, and fgetc() is not one of them. More generally, none of them are data-transfer functions. Therefore, if the error indicator is set for a stream before that stream is presented to fgetc() for reading, then it should still be set when that function returns, all other considerations notwithstanding. That covers these cases:*



        1  0   0   Unexpected
        1 1 0 Unexpected
        1 1 1 Input error or end-of-file


        It also covers this case with respect to the expected value of the error indicator, though it does not speak to whether it can actually happen:



        1  0   1   Normal reading of valid data with error indicator set!



      • fgetc() is specified to return EOF in every situation in which it is specified to set the end-of-file indicator on a stream. Therefore, if fgetc() returns anything other than EOF then it will not, on that call, have set the stream's error (or end-of-file) indicator. That covers these cases:



        0  0   0   Normal reading of valid data    
        0 0 1 Unexpected


        On the other hand, if fgetc() does return EOF then either the stream's end-of-file indicator or its error indicator should afterward be found set. But the standard distinguishes between these cases, and specifies that the user can distinguish them via the feof() and ferror() functions. That covers these cases:*



        0  1   0   End-of-file
        0 1 1 Input error



      • Finally, I concur that none of the behavior of fgetc() is conditioned on the initial state of the stream's error indicator. Provided only that the stream is not initially positioned at its end, and its end-of-file indicator is not initially set, "the fgetc function returns the next character from the input stream pointed to by stream." That establishes that this, the case of most interest, is in fact allowed:



        1  0   1   Normal reading of valid data with error indicator set!


        However, that the case is allowed in the abstract does not imply that it can be observed in practice. The details seem unspecified, and I would expect them to depend on the implementation of the driver serving the stream in question. It is entirely possible that having once encountered an error, the driver will continue to report an error on subsequent reads until reset appropriately, and perhaps longer. From the C perspective, that would be interpreted as an (additional) error occurring on each subsequent read, and nothing in the language specifications prevents that. Not even use of one of the functions that clear a stream's error indicator.





      If codes does not clear the error indicator before hand and wants to
      detect if a line of input had a rare input error, it seems to make
      sense to test !feof() and not ferror() to detect.



      Is checking ferror() potentially misleading? or have I missed something about the error indicator?




      I agree that if a stream's error indicator is initially set, its end-of-file indicator is not, and reading it with fgetc() returns EOF, then ferror() does not usefully distinguish between the end-of-file and error cases whereas feof() should.



      On the other hand, whether one can usefully continue to read a given stream after an error has been encountered on it depends on implementation and possibly on specific circumstances. That applies even if the error indicator is cleared via a clearerr() call, not to mention if the error indicator is not cleared.





      * Although I agree that there is an ambiguity with respect to EOF in the event that UCHAR_MAX > INT_MAX, I assert that that is just one of several reasons why such an implementation would be problematic. As a practical matter, therefore, I disregard such implementations as entirely hypothetical.






      share|improve this answer















      Assuming no UB, are 5 of the 8 possible and not the 3 unexpected ones?
      especially is valid input possible with error indicator set?




      Speaking specifically to the provisions of the standard, I'm inclined to agree with your analysis:





      • Few functions are specified to clear the error indicator of a stream, and fgetc() is not one of them. More generally, none of them are data-transfer functions. Therefore, if the error indicator is set for a stream before that stream is presented to fgetc() for reading, then it should still be set when that function returns, all other considerations notwithstanding. That covers these cases:*



        1  0   0   Unexpected
        1 1 0 Unexpected
        1 1 1 Input error or end-of-file


        It also covers this case with respect to the expected value of the error indicator, though it does not speak to whether it can actually happen:



        1  0   1   Normal reading of valid data with error indicator set!



      • fgetc() is specified to return EOF in every situation in which it is specified to set the end-of-file indicator on a stream. Therefore, if fgetc() returns anything other than EOF then it will not, on that call, have set the stream's error (or end-of-file) indicator. That covers these cases:



        0  0   0   Normal reading of valid data    
        0 0 1 Unexpected


        On the other hand, if fgetc() does return EOF then either the stream's end-of-file indicator or its error indicator should afterward be found set. But the standard distinguishes between these cases, and specifies that the user can distinguish them via the feof() and ferror() functions. That covers these cases:*



        0  1   0   End-of-file
        0 1 1 Input error



      • Finally, I concur that none of the behavior of fgetc() is conditioned on the initial state of the stream's error indicator. Provided only that the stream is not initially positioned at its end, and its end-of-file indicator is not initially set, "the fgetc function returns the next character from the input stream pointed to by stream." That establishes that this, the case of most interest, is in fact allowed:



        1  0   1   Normal reading of valid data with error indicator set!


        However, that the case is allowed in the abstract does not imply that it can be observed in practice. The details seem unspecified, and I would expect them to depend on the implementation of the driver serving the stream in question. It is entirely possible that having once encountered an error, the driver will continue to report an error on subsequent reads until reset appropriately, and perhaps longer. From the C perspective, that would be interpreted as an (additional) error occurring on each subsequent read, and nothing in the language specifications prevents that. Not even use of one of the functions that clear a stream's error indicator.





      If codes does not clear the error indicator before hand and wants to
      detect if a line of input had a rare input error, it seems to make
      sense to test !feof() and not ferror() to detect.



      Is checking ferror() potentially misleading? or have I missed something about the error indicator?




      I agree that if a stream's error indicator is initially set, its end-of-file indicator is not, and reading it with fgetc() returns EOF, then ferror() does not usefully distinguish between the end-of-file and error cases whereas feof() should.



      On the other hand, whether one can usefully continue to read a given stream after an error has been encountered on it depends on implementation and possibly on specific circumstances. That applies even if the error indicator is cleared via a clearerr() call, not to mention if the error indicator is not cleared.





      * Although I agree that there is an ambiguity with respect to EOF in the event that UCHAR_MAX > INT_MAX, I assert that that is just one of several reasons why such an implementation would be problematic. As a practical matter, therefore, I disregard such implementations as entirely hypothetical.







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Nov 14 at 18:30

























      answered Nov 13 at 6:14









      John Bollinger

      76.6k63771




      76.6k63771












      • Additional interest in "usefully continue to read a given stream after an error has been encountered" comes from reviewing input functions for robustness. Example: my_getline(). Such functions, when called, may or may not have the error indicator set. It is outside the function's control to prevent being called when a prior error had been encountered - just like fgetc(). Detection of input error seems to better rely on c == EOF && !feof(stdin) than c == EOF && ferror(...), so I was seeking other good ideas concerning input error.
        – chux
        Nov 14 at 11:33








      • 1




        @chux, I agree that having performed int c = fgetc(s); in a conforming C implementation, without knowledge of the initial state of stream s, testing for an error on that read via c == EOF && !feof(s) is valid, and it is more reliable than its analog involving ferror. If ferror is to be used instead, then the stream's error indicator must first be ensured clear. I am unaware of any alternatives fundamentally different from these.
        – John Bollinger
        Nov 14 at 14:14


















      • Additional interest in "usefully continue to read a given stream after an error has been encountered" comes from reviewing input functions for robustness. Example: my_getline(). Such functions, when called, may or may not have the error indicator set. It is outside the function's control to prevent being called when a prior error had been encountered - just like fgetc(). Detection of input error seems to better rely on c == EOF && !feof(stdin) than c == EOF && ferror(...), so I was seeking other good ideas concerning input error.
        – chux
        Nov 14 at 11:33








      • 1




        @chux, I agree that having performed int c = fgetc(s); in a conforming C implementation, without knowledge of the initial state of stream s, testing for an error on that read via c == EOF && !feof(s) is valid, and it is more reliable than its analog involving ferror. If ferror is to be used instead, then the stream's error indicator must first be ensured clear. I am unaware of any alternatives fundamentally different from these.
        – John Bollinger
        Nov 14 at 14:14
















      Additional interest in "usefully continue to read a given stream after an error has been encountered" comes from reviewing input functions for robustness. Example: my_getline(). Such functions, when called, may or may not have the error indicator set. It is outside the function's control to prevent being called when a prior error had been encountered - just like fgetc(). Detection of input error seems to better rely on c == EOF && !feof(stdin) than c == EOF && ferror(...), so I was seeking other good ideas concerning input error.
      – chux
      Nov 14 at 11:33






      Additional interest in "usefully continue to read a given stream after an error has been encountered" comes from reviewing input functions for robustness. Example: my_getline(). Such functions, when called, may or may not have the error indicator set. It is outside the function's control to prevent being called when a prior error had been encountered - just like fgetc(). Detection of input error seems to better rely on c == EOF && !feof(stdin) than c == EOF && ferror(...), so I was seeking other good ideas concerning input error.
      – chux
      Nov 14 at 11:33






      1




      1




      @chux, I agree that having performed int c = fgetc(s); in a conforming C implementation, without knowledge of the initial state of stream s, testing for an error on that read via c == EOF && !feof(s) is valid, and it is more reliable than its analog involving ferror. If ferror is to be used instead, then the stream's error indicator must first be ensured clear. I am unaware of any alternatives fundamentally different from these.
      – John Bollinger
      Nov 14 at 14:14




      @chux, I agree that having performed int c = fgetc(s); in a conforming C implementation, without knowledge of the initial state of stream s, testing for an error on that read via c == EOF && !feof(s) is valid, and it is more reliable than its analog involving ferror. If ferror is to be used instead, then the stream's error indicator must first be ensured clear. I am unaware of any alternatives fundamentally different from these.
      – John Bollinger
      Nov 14 at 14:14












      up vote
      1
      down vote













      Everything you say seems right, and ch==EOF && !feof(f) is the right way to check for new errors without interfering with error accumulation.






      share|improve this answer

























        up vote
        1
        down vote













        Everything you say seems right, and ch==EOF && !feof(f) is the right way to check for new errors without interfering with error accumulation.






        share|improve this answer























          up vote
          1
          down vote










          up vote
          1
          down vote









          Everything you say seems right, and ch==EOF && !feof(f) is the right way to check for new errors without interfering with error accumulation.






          share|improve this answer












          Everything you say seems right, and ch==EOF && !feof(f) is the right way to check for new errors without interfering with error accumulation.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 13 at 4:22









          R..

          154k25253559




          154k25253559






















              up vote
              1
              down vote













              Here is a very crude, very minimal program to explore the behaviour of GNU C library with respect to fgetc(), ferror(), and feof(), as requested by OP in a comment:



              #define  _POSIX_C_SOURCE  200809L
              #include <stdlib.h>
              #include <unistd.h>
              #include <stdio.h>
              #include <string.h>
              #include <signal.h>
              #include <errno.h>

              static volatile sig_atomic_t interrupted = 0;

              static void interrupt_handler(int signum)
              {
              interrupted = 1;
              }

              static int install_interrupt(const int signum)
              {
              struct sigaction act;

              memset(&act, 0, sizeof act);
              sigemptyset(&act.sa_mask);
              act.sa_handler = interrupt_handler;
              act.sa_flags = 0;
              if (sigaction(signum, &act, NULL) == -1)
              return -1;

              return 0;
              }

              int main(void)
              {
              int n, c;

              if (install_interrupt(SIGALRM)) {
              fprintf(stderr, "Cannot install SIGALRM handler: %s.n", strerror(errno));
              return EXIT_FAILURE;
              }

              if (ferror(stdin)) {
              fprintf(stderr, "Standard input is already in error state.n");
              return EXIT_FAILURE;
              }
              if (feof(stdin)) {
              fprintf(stderr, "Standard input is already in end-of-input state.n");
              return EXIT_FAILURE;
              }

              fprintf(stderr, "Testing stream error state. Please wait.n");

              alarm(1);
              c = fgetc(stdin);
              if (c != EOF) {
              fprintf(stderr, "Stream error state test failed.n");
              return EXIT_FAILURE;
              }

              fprintf(stderr, "fgetc(stdin) returned EOF.n");
              fprintf(stderr, "ferror(stdin) returns %d.n", ferror(stdin));
              fprintf(stderr, "feof(stdin) returns %d.n", feof(stdin));

              fprintf(stderr, "n");
              fprintf(stderr, "Testing stream end-of-input state. Please press Ctrl+D.n");
              c = fgetc(stdin);
              if (c != EOF) {
              fprintf(stderr, "fgetc() returned %d; EOF was expected.n", c);
              return EXIT_FAILURE;
              }
              fprintf(stderr, "fgetc(stdin) returned EOF.n");
              fprintf(stderr, "ferror(stdin) returns %d.n", ferror(stdin));
              fprintf(stderr, "feof(stdin) returns %d.n", feof(stdin));
              if (!ferror(stdin) || !feof(stdin)) {
              fprintf(stderr, "Expected error and end-of-file states; aborting.n");
              return EXIT_FAILURE;
              }

              fprintf(stderr, "n");
              fprintf(stderr, "Testing fgetc() when stream in error and end-of-file state.n");
              fprintf(stderr, "Please type something, then press Enter.n");
              n = 0;
              c = fgetc(stdin);
              while (c != EOF && c != 'n') {
              n++;
              c = fgetc(stdin);
              }
              if (c == EOF) {
              fprintf(stderr, "Further input is not possible.n");
              return EXIT_FAILURE;
              } else
              fprintf(stderr, "Further input is possible: %d characters (including Enter) read.n", n + 1);

              return EXIT_SUCCESS;
              }


              When I compile and run the above on Linux, the program will output



              Testing stream error state. Please wait.
              fgetc(stdin) returned EOF.
              ferror(stdin) returns 1.
              feof(stdin) returns 0.


              The error state was caused by having signal delivery interrupt an fgetc(stdin) call. As you can see, it does cause ferror(stdin) to return nonzero. Note that feof(stdin) returns 0, though.



              The output continues:



              Testing stream end-of-input state. Please press Ctrl+D.


              Pressing Ctrl+C yields output



              fgetc(stdin) returned EOF.
              ferror(stdin) returns 1.
              feof(stdin) returns 1.


              At this point, the standard input is in both error and end-of-file states. The output continues:



              Testing fgetc() when stream in error and end-of-file state.
              Please type something, then press Enter.


              If we now type say O K Enter, we get



              Further input is possible: 3 characters (including Enter) read.


              This proves that at least the GNU C library implementation does not check the stream error or end-of-file status at all. It will simply try to read more data (using the underlying read() operation in POSIXy systems).






              share|improve this answer





















              • I also found similar results, yet tend to think it is non-conforming to the standard. (IOWs, a bug in that version). I also noticed that the end-of-file flag was cleared by fgetc() call with 5 key "xn", Ctrl d, ".n" sequence with the '.' key.
                – chux
                Nov 14 at 18:57












              • @chux: On POSIXy systems, the EOF behaviour kinda makes sense, because if the file gets appended to after we read it till the end, we'll want to get the appended data; and since there is no cleareof() function, reopening the file would be the only way to do that otherwise. Whether any of this is standards-conformant, I have no opinion: I've decided to steer away from language-lawyer. (If it is a bug in glibc, getting it fixed is a quixotic fight against people who believe they know the standards better than anyone else. Not worth the effort, IMO.)
                – Nominal Animal
                Nov 14 at 19:09










              • Re: "there is no cleareof()". Would not clearerr(istream) be sufficient in lieu of reopening the file? IAC, thanks for the exploring the corners of C I/O.
                – chux
                Nov 14 at 19:14












              • @NominalAnimal For the record, if you believe you have found a bug in glibc and you don't feel like arguing with Joseph and/or Paul Eggert about it, you can email me and I'll do it. Ulrich is no longer involved.
                – zwol
                Nov 14 at 19:27












              • @zwol: Yeah, libio/getc.c:_IO_getc() and libio/getc_u.c:__getc_unlocked() are still missing an _IO_ferror_unlocked() check in HEAD. I'd recommend turning _IO_getc_unlocked() into a function that does the check, and returns __getc_unlocked_body(). Also, an RFC to the devs: perhaps change _IO_EOF_SEEN in libio/bits/types/struct_FILE.h to 0x0030, so that feof() returns nonzero if eof or error.
                – Nominal Animal
                Nov 14 at 20:58

















              up vote
              1
              down vote













              Here is a very crude, very minimal program to explore the behaviour of GNU C library with respect to fgetc(), ferror(), and feof(), as requested by OP in a comment:



              #define  _POSIX_C_SOURCE  200809L
              #include <stdlib.h>
              #include <unistd.h>
              #include <stdio.h>
              #include <string.h>
              #include <signal.h>
              #include <errno.h>

              static volatile sig_atomic_t interrupted = 0;

              static void interrupt_handler(int signum)
              {
              interrupted = 1;
              }

              static int install_interrupt(const int signum)
              {
              struct sigaction act;

              memset(&act, 0, sizeof act);
              sigemptyset(&act.sa_mask);
              act.sa_handler = interrupt_handler;
              act.sa_flags = 0;
              if (sigaction(signum, &act, NULL) == -1)
              return -1;

              return 0;
              }

              int main(void)
              {
              int n, c;

              if (install_interrupt(SIGALRM)) {
              fprintf(stderr, "Cannot install SIGALRM handler: %s.n", strerror(errno));
              return EXIT_FAILURE;
              }

              if (ferror(stdin)) {
              fprintf(stderr, "Standard input is already in error state.n");
              return EXIT_FAILURE;
              }
              if (feof(stdin)) {
              fprintf(stderr, "Standard input is already in end-of-input state.n");
              return EXIT_FAILURE;
              }

              fprintf(stderr, "Testing stream error state. Please wait.n");

              alarm(1);
              c = fgetc(stdin);
              if (c != EOF) {
              fprintf(stderr, "Stream error state test failed.n");
              return EXIT_FAILURE;
              }

              fprintf(stderr, "fgetc(stdin) returned EOF.n");
              fprintf(stderr, "ferror(stdin) returns %d.n", ferror(stdin));
              fprintf(stderr, "feof(stdin) returns %d.n", feof(stdin));

              fprintf(stderr, "n");
              fprintf(stderr, "Testing stream end-of-input state. Please press Ctrl+D.n");
              c = fgetc(stdin);
              if (c != EOF) {
              fprintf(stderr, "fgetc() returned %d; EOF was expected.n", c);
              return EXIT_FAILURE;
              }
              fprintf(stderr, "fgetc(stdin) returned EOF.n");
              fprintf(stderr, "ferror(stdin) returns %d.n", ferror(stdin));
              fprintf(stderr, "feof(stdin) returns %d.n", feof(stdin));
              if (!ferror(stdin) || !feof(stdin)) {
              fprintf(stderr, "Expected error and end-of-file states; aborting.n");
              return EXIT_FAILURE;
              }

              fprintf(stderr, "n");
              fprintf(stderr, "Testing fgetc() when stream in error and end-of-file state.n");
              fprintf(stderr, "Please type something, then press Enter.n");
              n = 0;
              c = fgetc(stdin);
              while (c != EOF && c != 'n') {
              n++;
              c = fgetc(stdin);
              }
              if (c == EOF) {
              fprintf(stderr, "Further input is not possible.n");
              return EXIT_FAILURE;
              } else
              fprintf(stderr, "Further input is possible: %d characters (including Enter) read.n", n + 1);

              return EXIT_SUCCESS;
              }


              When I compile and run the above on Linux, the program will output



              Testing stream error state. Please wait.
              fgetc(stdin) returned EOF.
              ferror(stdin) returns 1.
              feof(stdin) returns 0.


              The error state was caused by having signal delivery interrupt an fgetc(stdin) call. As you can see, it does cause ferror(stdin) to return nonzero. Note that feof(stdin) returns 0, though.



              The output continues:



              Testing stream end-of-input state. Please press Ctrl+D.


              Pressing Ctrl+C yields output



              fgetc(stdin) returned EOF.
              ferror(stdin) returns 1.
              feof(stdin) returns 1.


              At this point, the standard input is in both error and end-of-file states. The output continues:



              Testing fgetc() when stream in error and end-of-file state.
              Please type something, then press Enter.


              If we now type say O K Enter, we get



              Further input is possible: 3 characters (including Enter) read.


              This proves that at least the GNU C library implementation does not check the stream error or end-of-file status at all. It will simply try to read more data (using the underlying read() operation in POSIXy systems).






              share|improve this answer





















              • I also found similar results, yet tend to think it is non-conforming to the standard. (IOWs, a bug in that version). I also noticed that the end-of-file flag was cleared by fgetc() call with 5 key "xn", Ctrl d, ".n" sequence with the '.' key.
                – chux
                Nov 14 at 18:57












              • @chux: On POSIXy systems, the EOF behaviour kinda makes sense, because if the file gets appended to after we read it till the end, we'll want to get the appended data; and since there is no cleareof() function, reopening the file would be the only way to do that otherwise. Whether any of this is standards-conformant, I have no opinion: I've decided to steer away from language-lawyer. (If it is a bug in glibc, getting it fixed is a quixotic fight against people who believe they know the standards better than anyone else. Not worth the effort, IMO.)
                – Nominal Animal
                Nov 14 at 19:09










              • Re: "there is no cleareof()". Would not clearerr(istream) be sufficient in lieu of reopening the file? IAC, thanks for the exploring the corners of C I/O.
                – chux
                Nov 14 at 19:14












              • @NominalAnimal For the record, if you believe you have found a bug in glibc and you don't feel like arguing with Joseph and/or Paul Eggert about it, you can email me and I'll do it. Ulrich is no longer involved.
                – zwol
                Nov 14 at 19:27












              • @zwol: Yeah, libio/getc.c:_IO_getc() and libio/getc_u.c:__getc_unlocked() are still missing an _IO_ferror_unlocked() check in HEAD. I'd recommend turning _IO_getc_unlocked() into a function that does the check, and returns __getc_unlocked_body(). Also, an RFC to the devs: perhaps change _IO_EOF_SEEN in libio/bits/types/struct_FILE.h to 0x0030, so that feof() returns nonzero if eof or error.
                – Nominal Animal
                Nov 14 at 20:58















              up vote
              1
              down vote










              up vote
              1
              down vote









              Here is a very crude, very minimal program to explore the behaviour of GNU C library with respect to fgetc(), ferror(), and feof(), as requested by OP in a comment:



              #define  _POSIX_C_SOURCE  200809L
              #include <stdlib.h>
              #include <unistd.h>
              #include <stdio.h>
              #include <string.h>
              #include <signal.h>
              #include <errno.h>

              static volatile sig_atomic_t interrupted = 0;

              static void interrupt_handler(int signum)
              {
              interrupted = 1;
              }

              static int install_interrupt(const int signum)
              {
              struct sigaction act;

              memset(&act, 0, sizeof act);
              sigemptyset(&act.sa_mask);
              act.sa_handler = interrupt_handler;
              act.sa_flags = 0;
              if (sigaction(signum, &act, NULL) == -1)
              return -1;

              return 0;
              }

              int main(void)
              {
              int n, c;

              if (install_interrupt(SIGALRM)) {
              fprintf(stderr, "Cannot install SIGALRM handler: %s.n", strerror(errno));
              return EXIT_FAILURE;
              }

              if (ferror(stdin)) {
              fprintf(stderr, "Standard input is already in error state.n");
              return EXIT_FAILURE;
              }
              if (feof(stdin)) {
              fprintf(stderr, "Standard input is already in end-of-input state.n");
              return EXIT_FAILURE;
              }

              fprintf(stderr, "Testing stream error state. Please wait.n");

              alarm(1);
              c = fgetc(stdin);
              if (c != EOF) {
              fprintf(stderr, "Stream error state test failed.n");
              return EXIT_FAILURE;
              }

              fprintf(stderr, "fgetc(stdin) returned EOF.n");
              fprintf(stderr, "ferror(stdin) returns %d.n", ferror(stdin));
              fprintf(stderr, "feof(stdin) returns %d.n", feof(stdin));

              fprintf(stderr, "n");
              fprintf(stderr, "Testing stream end-of-input state. Please press Ctrl+D.n");
              c = fgetc(stdin);
              if (c != EOF) {
              fprintf(stderr, "fgetc() returned %d; EOF was expected.n", c);
              return EXIT_FAILURE;
              }
              fprintf(stderr, "fgetc(stdin) returned EOF.n");
              fprintf(stderr, "ferror(stdin) returns %d.n", ferror(stdin));
              fprintf(stderr, "feof(stdin) returns %d.n", feof(stdin));
              if (!ferror(stdin) || !feof(stdin)) {
              fprintf(stderr, "Expected error and end-of-file states; aborting.n");
              return EXIT_FAILURE;
              }

              fprintf(stderr, "n");
              fprintf(stderr, "Testing fgetc() when stream in error and end-of-file state.n");
              fprintf(stderr, "Please type something, then press Enter.n");
              n = 0;
              c = fgetc(stdin);
              while (c != EOF && c != 'n') {
              n++;
              c = fgetc(stdin);
              }
              if (c == EOF) {
              fprintf(stderr, "Further input is not possible.n");
              return EXIT_FAILURE;
              } else
              fprintf(stderr, "Further input is possible: %d characters (including Enter) read.n", n + 1);

              return EXIT_SUCCESS;
              }


              When I compile and run the above on Linux, the program will output



              Testing stream error state. Please wait.
              fgetc(stdin) returned EOF.
              ferror(stdin) returns 1.
              feof(stdin) returns 0.


              The error state was caused by having signal delivery interrupt an fgetc(stdin) call. As you can see, it does cause ferror(stdin) to return nonzero. Note that feof(stdin) returns 0, though.



              The output continues:



              Testing stream end-of-input state. Please press Ctrl+D.


              Pressing Ctrl+C yields output



              fgetc(stdin) returned EOF.
              ferror(stdin) returns 1.
              feof(stdin) returns 1.


              At this point, the standard input is in both error and end-of-file states. The output continues:



              Testing fgetc() when stream in error and end-of-file state.
              Please type something, then press Enter.


              If we now type say O K Enter, we get



              Further input is possible: 3 characters (including Enter) read.


              This proves that at least the GNU C library implementation does not check the stream error or end-of-file status at all. It will simply try to read more data (using the underlying read() operation in POSIXy systems).






              share|improve this answer












              Here is a very crude, very minimal program to explore the behaviour of GNU C library with respect to fgetc(), ferror(), and feof(), as requested by OP in a comment:



              #define  _POSIX_C_SOURCE  200809L
              #include <stdlib.h>
              #include <unistd.h>
              #include <stdio.h>
              #include <string.h>
              #include <signal.h>
              #include <errno.h>

              static volatile sig_atomic_t interrupted = 0;

              static void interrupt_handler(int signum)
              {
              interrupted = 1;
              }

              static int install_interrupt(const int signum)
              {
              struct sigaction act;

              memset(&act, 0, sizeof act);
              sigemptyset(&act.sa_mask);
              act.sa_handler = interrupt_handler;
              act.sa_flags = 0;
              if (sigaction(signum, &act, NULL) == -1)
              return -1;

              return 0;
              }

              int main(void)
              {
              int n, c;

              if (install_interrupt(SIGALRM)) {
              fprintf(stderr, "Cannot install SIGALRM handler: %s.n", strerror(errno));
              return EXIT_FAILURE;
              }

              if (ferror(stdin)) {
              fprintf(stderr, "Standard input is already in error state.n");
              return EXIT_FAILURE;
              }
              if (feof(stdin)) {
              fprintf(stderr, "Standard input is already in end-of-input state.n");
              return EXIT_FAILURE;
              }

              fprintf(stderr, "Testing stream error state. Please wait.n");

              alarm(1);
              c = fgetc(stdin);
              if (c != EOF) {
              fprintf(stderr, "Stream error state test failed.n");
              return EXIT_FAILURE;
              }

              fprintf(stderr, "fgetc(stdin) returned EOF.n");
              fprintf(stderr, "ferror(stdin) returns %d.n", ferror(stdin));
              fprintf(stderr, "feof(stdin) returns %d.n", feof(stdin));

              fprintf(stderr, "n");
              fprintf(stderr, "Testing stream end-of-input state. Please press Ctrl+D.n");
              c = fgetc(stdin);
              if (c != EOF) {
              fprintf(stderr, "fgetc() returned %d; EOF was expected.n", c);
              return EXIT_FAILURE;
              }
              fprintf(stderr, "fgetc(stdin) returned EOF.n");
              fprintf(stderr, "ferror(stdin) returns %d.n", ferror(stdin));
              fprintf(stderr, "feof(stdin) returns %d.n", feof(stdin));
              if (!ferror(stdin) || !feof(stdin)) {
              fprintf(stderr, "Expected error and end-of-file states; aborting.n");
              return EXIT_FAILURE;
              }

              fprintf(stderr, "n");
              fprintf(stderr, "Testing fgetc() when stream in error and end-of-file state.n");
              fprintf(stderr, "Please type something, then press Enter.n");
              n = 0;
              c = fgetc(stdin);
              while (c != EOF && c != 'n') {
              n++;
              c = fgetc(stdin);
              }
              if (c == EOF) {
              fprintf(stderr, "Further input is not possible.n");
              return EXIT_FAILURE;
              } else
              fprintf(stderr, "Further input is possible: %d characters (including Enter) read.n", n + 1);

              return EXIT_SUCCESS;
              }


              When I compile and run the above on Linux, the program will output



              Testing stream error state. Please wait.
              fgetc(stdin) returned EOF.
              ferror(stdin) returns 1.
              feof(stdin) returns 0.


              The error state was caused by having signal delivery interrupt an fgetc(stdin) call. As you can see, it does cause ferror(stdin) to return nonzero. Note that feof(stdin) returns 0, though.



              The output continues:



              Testing stream end-of-input state. Please press Ctrl+D.


              Pressing Ctrl+C yields output



              fgetc(stdin) returned EOF.
              ferror(stdin) returns 1.
              feof(stdin) returns 1.


              At this point, the standard input is in both error and end-of-file states. The output continues:



              Testing fgetc() when stream in error and end-of-file state.
              Please type something, then press Enter.


              If we now type say O K Enter, we get



              Further input is possible: 3 characters (including Enter) read.


              This proves that at least the GNU C library implementation does not check the stream error or end-of-file status at all. It will simply try to read more data (using the underlying read() operation in POSIXy systems).







              share|improve this answer












              share|improve this answer



              share|improve this answer










              answered Nov 14 at 16:04









              Nominal Animal

              27.9k33259




              27.9k33259












              • I also found similar results, yet tend to think it is non-conforming to the standard. (IOWs, a bug in that version). I also noticed that the end-of-file flag was cleared by fgetc() call with 5 key "xn", Ctrl d, ".n" sequence with the '.' key.
                – chux
                Nov 14 at 18:57












              • @chux: On POSIXy systems, the EOF behaviour kinda makes sense, because if the file gets appended to after we read it till the end, we'll want to get the appended data; and since there is no cleareof() function, reopening the file would be the only way to do that otherwise. Whether any of this is standards-conformant, I have no opinion: I've decided to steer away from language-lawyer. (If it is a bug in glibc, getting it fixed is a quixotic fight against people who believe they know the standards better than anyone else. Not worth the effort, IMO.)
                – Nominal Animal
                Nov 14 at 19:09










              • Re: "there is no cleareof()". Would not clearerr(istream) be sufficient in lieu of reopening the file? IAC, thanks for the exploring the corners of C I/O.
                – chux
                Nov 14 at 19:14












              • @NominalAnimal For the record, if you believe you have found a bug in glibc and you don't feel like arguing with Joseph and/or Paul Eggert about it, you can email me and I'll do it. Ulrich is no longer involved.
                – zwol
                Nov 14 at 19:27












              • @zwol: Yeah, libio/getc.c:_IO_getc() and libio/getc_u.c:__getc_unlocked() are still missing an _IO_ferror_unlocked() check in HEAD. I'd recommend turning _IO_getc_unlocked() into a function that does the check, and returns __getc_unlocked_body(). Also, an RFC to the devs: perhaps change _IO_EOF_SEEN in libio/bits/types/struct_FILE.h to 0x0030, so that feof() returns nonzero if eof or error.
                – Nominal Animal
                Nov 14 at 20:58




















              • I also found similar results, yet tend to think it is non-conforming to the standard. (IOWs, a bug in that version). I also noticed that the end-of-file flag was cleared by fgetc() call with 5 key "xn", Ctrl d, ".n" sequence with the '.' key.
                – chux
                Nov 14 at 18:57












              • @chux: On POSIXy systems, the EOF behaviour kinda makes sense, because if the file gets appended to after we read it till the end, we'll want to get the appended data; and since there is no cleareof() function, reopening the file would be the only way to do that otherwise. Whether any of this is standards-conformant, I have no opinion: I've decided to steer away from language-lawyer. (If it is a bug in glibc, getting it fixed is a quixotic fight against people who believe they know the standards better than anyone else. Not worth the effort, IMO.)
                – Nominal Animal
                Nov 14 at 19:09










              • Re: "there is no cleareof()". Would not clearerr(istream) be sufficient in lieu of reopening the file? IAC, thanks for the exploring the corners of C I/O.
                – chux
                Nov 14 at 19:14












              • @NominalAnimal For the record, if you believe you have found a bug in glibc and you don't feel like arguing with Joseph and/or Paul Eggert about it, you can email me and I'll do it. Ulrich is no longer involved.
                – zwol
                Nov 14 at 19:27












              • @zwol: Yeah, libio/getc.c:_IO_getc() and libio/getc_u.c:__getc_unlocked() are still missing an _IO_ferror_unlocked() check in HEAD. I'd recommend turning _IO_getc_unlocked() into a function that does the check, and returns __getc_unlocked_body(). Also, an RFC to the devs: perhaps change _IO_EOF_SEEN in libio/bits/types/struct_FILE.h to 0x0030, so that feof() returns nonzero if eof or error.
                – Nominal Animal
                Nov 14 at 20:58


















              I also found similar results, yet tend to think it is non-conforming to the standard. (IOWs, a bug in that version). I also noticed that the end-of-file flag was cleared by fgetc() call with 5 key "xn", Ctrl d, ".n" sequence with the '.' key.
              – chux
              Nov 14 at 18:57






              I also found similar results, yet tend to think it is non-conforming to the standard. (IOWs, a bug in that version). I also noticed that the end-of-file flag was cleared by fgetc() call with 5 key "xn", Ctrl d, ".n" sequence with the '.' key.
              – chux
              Nov 14 at 18:57














              @chux: On POSIXy systems, the EOF behaviour kinda makes sense, because if the file gets appended to after we read it till the end, we'll want to get the appended data; and since there is no cleareof() function, reopening the file would be the only way to do that otherwise. Whether any of this is standards-conformant, I have no opinion: I've decided to steer away from language-lawyer. (If it is a bug in glibc, getting it fixed is a quixotic fight against people who believe they know the standards better than anyone else. Not worth the effort, IMO.)
              – Nominal Animal
              Nov 14 at 19:09




              @chux: On POSIXy systems, the EOF behaviour kinda makes sense, because if the file gets appended to after we read it till the end, we'll want to get the appended data; and since there is no cleareof() function, reopening the file would be the only way to do that otherwise. Whether any of this is standards-conformant, I have no opinion: I've decided to steer away from language-lawyer. (If it is a bug in glibc, getting it fixed is a quixotic fight against people who believe they know the standards better than anyone else. Not worth the effort, IMO.)
              – Nominal Animal
              Nov 14 at 19:09












              Re: "there is no cleareof()". Would not clearerr(istream) be sufficient in lieu of reopening the file? IAC, thanks for the exploring the corners of C I/O.
              – chux
              Nov 14 at 19:14






              Re: "there is no cleareof()". Would not clearerr(istream) be sufficient in lieu of reopening the file? IAC, thanks for the exploring the corners of C I/O.
              – chux
              Nov 14 at 19:14














              @NominalAnimal For the record, if you believe you have found a bug in glibc and you don't feel like arguing with Joseph and/or Paul Eggert about it, you can email me and I'll do it. Ulrich is no longer involved.
              – zwol
              Nov 14 at 19:27






              @NominalAnimal For the record, if you believe you have found a bug in glibc and you don't feel like arguing with Joseph and/or Paul Eggert about it, you can email me and I'll do it. Ulrich is no longer involved.
              – zwol
              Nov 14 at 19:27














              @zwol: Yeah, libio/getc.c:_IO_getc() and libio/getc_u.c:__getc_unlocked() are still missing an _IO_ferror_unlocked() check in HEAD. I'd recommend turning _IO_getc_unlocked() into a function that does the check, and returns __getc_unlocked_body(). Also, an RFC to the devs: perhaps change _IO_EOF_SEEN in libio/bits/types/struct_FILE.h to 0x0030, so that feof() returns nonzero if eof or error.
              – Nominal Animal
              Nov 14 at 20:58






              @zwol: Yeah, libio/getc.c:_IO_getc() and libio/getc_u.c:__getc_unlocked() are still missing an _IO_ferror_unlocked() check in HEAD. I'd recommend turning _IO_getc_unlocked() into a function that does the check, and returns __getc_unlocked_body(). Also, an RFC to the devs: perhaps change _IO_EOF_SEEN in libio/bits/types/struct_FILE.h to 0x0030, so that feof() returns nonzero if eof or error.
              – Nominal Animal
              Nov 14 at 20:58












              up vote
              0
              down vote













              My reading of the standard is that it doesn't explicitly say fgetc is allowed to return a non-EOF value if the error indicator was already set on the stream on entry, but it doesn't explicitly say that it can't, either. I sympathize with Nominal Animal's observation (which I shall hoist from comments on his answer in case it gets deleted or moved to chat; allow me to grind my personal axe for a moment and observe that the policy of treating comments as "ephemeral" is harmful and should be abolished):




              IMHO the standard is then bass-ackwards: there is no practical need for EOF to be sticky, but if error is not sticky, then there is a real risk of accidentally missing errors.




              However, if existing implementations are all consistently not treating error as sticky, changing the behavior will be very hard to sell to the committee. Therefore, I am soliciting tests from the community:



              Below is a shortened, non-interactive version of Nominal Animal's test program. It only looks at the behavior of fgetc after a read error, not after EOF. It uses SIGALRM to interrupt a read, instead of control-C, so you don't have to do anything but run it.



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

              static _Noreturn void
              perror_exit (const char *msg)
              {
              perror (msg);
              exit (1);
              }

              static void
              handler (int unused)
              {
              }

              int
              main (void)
              {
              struct sigaction sa;
              int pipefd[2];
              FILE *fp;
              int ch, pa;

              setvbuf (stdout, 0, _IOLBF, 0);

              sa.sa_handler = handler;
              sa.sa_flags = 0; /* DO interrupt blocking system calls */
              sigemptyset (&sa.sa_mask);
              if (sigaction (SIGALRM, &sa, 0))
              perror_exit ("sigaction");

              if (pipe (pipefd))
              perror_exit ("pipe");

              fp = fdopen (pipefd[0], "r");
              if (!fp)
              perror_exit ("fdopen");

              printf ("before fgetc 1, feof = %d ferror = %dn",
              feof (fp), ferror (fp));

              alarm (1);
              ch = fgetc (fp);

              if (ch == EOF)
              printf ("after fgetc 1, ch = EOF feof = %d ferror = %dn",
              feof (fp), ferror (fp));
              else
              printf ("after fgetc 1, ch = '%c' feof = %d ferror = %dn",
              ch, feof (fp), ferror (fp));

              write (pipefd[1], "x", 1);
              alarm (1);
              ch = fgetc (fp);
              pa = alarm (0);

              printf ("after fgetc 2, alarm %sn",
              pa ? "did not fire" : "fired");

              if (ch == EOF)
              printf ("after fgetc 2, ch = EOF feof = %d ferror = %dn",
              feof (fp), ferror (fp));
              else
              printf ("after fgetc 2, ch = '%c' feof = %d ferror = %dn",
              ch, feof (fp), ferror (fp));

              return 0;
              }


              On all three of Linux with glibc 2.27, NetBSD 7.1.2, and FreeBSD 11.2-RELEASE-p4 (which is all of the Unixes I can get at at the moment), this program prints



              before fgetc 1, feof = 0 ferror = 0
              after fgetc 1, ch = EOF feof = 0 ferror = 1
              after fgetc 2, alarm did not fire
              after fgetc 2, ch = 'x' feof = 0 ferror = 1


              consistent with John Bollinger's observation that




              the case of most interest, is in fact allowed:



              1  0   1   Normal reading of valid data with error indicator set!



              I would particularly like to know what this program prints when run on alternative Linux-based C libraries (e.g. musl, bionic); Unixes which are not Linux nor are they BSD-phylum; and Windows. If you've got anything even more exotic please try that too. I'm marking this post community wiki; please edit it to add test results.






              share|improve this answer



























                up vote
                0
                down vote













                My reading of the standard is that it doesn't explicitly say fgetc is allowed to return a non-EOF value if the error indicator was already set on the stream on entry, but it doesn't explicitly say that it can't, either. I sympathize with Nominal Animal's observation (which I shall hoist from comments on his answer in case it gets deleted or moved to chat; allow me to grind my personal axe for a moment and observe that the policy of treating comments as "ephemeral" is harmful and should be abolished):




                IMHO the standard is then bass-ackwards: there is no practical need for EOF to be sticky, but if error is not sticky, then there is a real risk of accidentally missing errors.




                However, if existing implementations are all consistently not treating error as sticky, changing the behavior will be very hard to sell to the committee. Therefore, I am soliciting tests from the community:



                Below is a shortened, non-interactive version of Nominal Animal's test program. It only looks at the behavior of fgetc after a read error, not after EOF. It uses SIGALRM to interrupt a read, instead of control-C, so you don't have to do anything but run it.



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

                static _Noreturn void
                perror_exit (const char *msg)
                {
                perror (msg);
                exit (1);
                }

                static void
                handler (int unused)
                {
                }

                int
                main (void)
                {
                struct sigaction sa;
                int pipefd[2];
                FILE *fp;
                int ch, pa;

                setvbuf (stdout, 0, _IOLBF, 0);

                sa.sa_handler = handler;
                sa.sa_flags = 0; /* DO interrupt blocking system calls */
                sigemptyset (&sa.sa_mask);
                if (sigaction (SIGALRM, &sa, 0))
                perror_exit ("sigaction");

                if (pipe (pipefd))
                perror_exit ("pipe");

                fp = fdopen (pipefd[0], "r");
                if (!fp)
                perror_exit ("fdopen");

                printf ("before fgetc 1, feof = %d ferror = %dn",
                feof (fp), ferror (fp));

                alarm (1);
                ch = fgetc (fp);

                if (ch == EOF)
                printf ("after fgetc 1, ch = EOF feof = %d ferror = %dn",
                feof (fp), ferror (fp));
                else
                printf ("after fgetc 1, ch = '%c' feof = %d ferror = %dn",
                ch, feof (fp), ferror (fp));

                write (pipefd[1], "x", 1);
                alarm (1);
                ch = fgetc (fp);
                pa = alarm (0);

                printf ("after fgetc 2, alarm %sn",
                pa ? "did not fire" : "fired");

                if (ch == EOF)
                printf ("after fgetc 2, ch = EOF feof = %d ferror = %dn",
                feof (fp), ferror (fp));
                else
                printf ("after fgetc 2, ch = '%c' feof = %d ferror = %dn",
                ch, feof (fp), ferror (fp));

                return 0;
                }


                On all three of Linux with glibc 2.27, NetBSD 7.1.2, and FreeBSD 11.2-RELEASE-p4 (which is all of the Unixes I can get at at the moment), this program prints



                before fgetc 1, feof = 0 ferror = 0
                after fgetc 1, ch = EOF feof = 0 ferror = 1
                after fgetc 2, alarm did not fire
                after fgetc 2, ch = 'x' feof = 0 ferror = 1


                consistent with John Bollinger's observation that




                the case of most interest, is in fact allowed:



                1  0   1   Normal reading of valid data with error indicator set!



                I would particularly like to know what this program prints when run on alternative Linux-based C libraries (e.g. musl, bionic); Unixes which are not Linux nor are they BSD-phylum; and Windows. If you've got anything even more exotic please try that too. I'm marking this post community wiki; please edit it to add test results.






                share|improve this answer

























                  up vote
                  0
                  down vote










                  up vote
                  0
                  down vote









                  My reading of the standard is that it doesn't explicitly say fgetc is allowed to return a non-EOF value if the error indicator was already set on the stream on entry, but it doesn't explicitly say that it can't, either. I sympathize with Nominal Animal's observation (which I shall hoist from comments on his answer in case it gets deleted or moved to chat; allow me to grind my personal axe for a moment and observe that the policy of treating comments as "ephemeral" is harmful and should be abolished):




                  IMHO the standard is then bass-ackwards: there is no practical need for EOF to be sticky, but if error is not sticky, then there is a real risk of accidentally missing errors.




                  However, if existing implementations are all consistently not treating error as sticky, changing the behavior will be very hard to sell to the committee. Therefore, I am soliciting tests from the community:



                  Below is a shortened, non-interactive version of Nominal Animal's test program. It only looks at the behavior of fgetc after a read error, not after EOF. It uses SIGALRM to interrupt a read, instead of control-C, so you don't have to do anything but run it.



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

                  static _Noreturn void
                  perror_exit (const char *msg)
                  {
                  perror (msg);
                  exit (1);
                  }

                  static void
                  handler (int unused)
                  {
                  }

                  int
                  main (void)
                  {
                  struct sigaction sa;
                  int pipefd[2];
                  FILE *fp;
                  int ch, pa;

                  setvbuf (stdout, 0, _IOLBF, 0);

                  sa.sa_handler = handler;
                  sa.sa_flags = 0; /* DO interrupt blocking system calls */
                  sigemptyset (&sa.sa_mask);
                  if (sigaction (SIGALRM, &sa, 0))
                  perror_exit ("sigaction");

                  if (pipe (pipefd))
                  perror_exit ("pipe");

                  fp = fdopen (pipefd[0], "r");
                  if (!fp)
                  perror_exit ("fdopen");

                  printf ("before fgetc 1, feof = %d ferror = %dn",
                  feof (fp), ferror (fp));

                  alarm (1);
                  ch = fgetc (fp);

                  if (ch == EOF)
                  printf ("after fgetc 1, ch = EOF feof = %d ferror = %dn",
                  feof (fp), ferror (fp));
                  else
                  printf ("after fgetc 1, ch = '%c' feof = %d ferror = %dn",
                  ch, feof (fp), ferror (fp));

                  write (pipefd[1], "x", 1);
                  alarm (1);
                  ch = fgetc (fp);
                  pa = alarm (0);

                  printf ("after fgetc 2, alarm %sn",
                  pa ? "did not fire" : "fired");

                  if (ch == EOF)
                  printf ("after fgetc 2, ch = EOF feof = %d ferror = %dn",
                  feof (fp), ferror (fp));
                  else
                  printf ("after fgetc 2, ch = '%c' feof = %d ferror = %dn",
                  ch, feof (fp), ferror (fp));

                  return 0;
                  }


                  On all three of Linux with glibc 2.27, NetBSD 7.1.2, and FreeBSD 11.2-RELEASE-p4 (which is all of the Unixes I can get at at the moment), this program prints



                  before fgetc 1, feof = 0 ferror = 0
                  after fgetc 1, ch = EOF feof = 0 ferror = 1
                  after fgetc 2, alarm did not fire
                  after fgetc 2, ch = 'x' feof = 0 ferror = 1


                  consistent with John Bollinger's observation that




                  the case of most interest, is in fact allowed:



                  1  0   1   Normal reading of valid data with error indicator set!



                  I would particularly like to know what this program prints when run on alternative Linux-based C libraries (e.g. musl, bionic); Unixes which are not Linux nor are they BSD-phylum; and Windows. If you've got anything even more exotic please try that too. I'm marking this post community wiki; please edit it to add test results.






                  share|improve this answer














                  My reading of the standard is that it doesn't explicitly say fgetc is allowed to return a non-EOF value if the error indicator was already set on the stream on entry, but it doesn't explicitly say that it can't, either. I sympathize with Nominal Animal's observation (which I shall hoist from comments on his answer in case it gets deleted or moved to chat; allow me to grind my personal axe for a moment and observe that the policy of treating comments as "ephemeral" is harmful and should be abolished):




                  IMHO the standard is then bass-ackwards: there is no practical need for EOF to be sticky, but if error is not sticky, then there is a real risk of accidentally missing errors.




                  However, if existing implementations are all consistently not treating error as sticky, changing the behavior will be very hard to sell to the committee. Therefore, I am soliciting tests from the community:



                  Below is a shortened, non-interactive version of Nominal Animal's test program. It only looks at the behavior of fgetc after a read error, not after EOF. It uses SIGALRM to interrupt a read, instead of control-C, so you don't have to do anything but run it.



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

                  static _Noreturn void
                  perror_exit (const char *msg)
                  {
                  perror (msg);
                  exit (1);
                  }

                  static void
                  handler (int unused)
                  {
                  }

                  int
                  main (void)
                  {
                  struct sigaction sa;
                  int pipefd[2];
                  FILE *fp;
                  int ch, pa;

                  setvbuf (stdout, 0, _IOLBF, 0);

                  sa.sa_handler = handler;
                  sa.sa_flags = 0; /* DO interrupt blocking system calls */
                  sigemptyset (&sa.sa_mask);
                  if (sigaction (SIGALRM, &sa, 0))
                  perror_exit ("sigaction");

                  if (pipe (pipefd))
                  perror_exit ("pipe");

                  fp = fdopen (pipefd[0], "r");
                  if (!fp)
                  perror_exit ("fdopen");

                  printf ("before fgetc 1, feof = %d ferror = %dn",
                  feof (fp), ferror (fp));

                  alarm (1);
                  ch = fgetc (fp);

                  if (ch == EOF)
                  printf ("after fgetc 1, ch = EOF feof = %d ferror = %dn",
                  feof (fp), ferror (fp));
                  else
                  printf ("after fgetc 1, ch = '%c' feof = %d ferror = %dn",
                  ch, feof (fp), ferror (fp));

                  write (pipefd[1], "x", 1);
                  alarm (1);
                  ch = fgetc (fp);
                  pa = alarm (0);

                  printf ("after fgetc 2, alarm %sn",
                  pa ? "did not fire" : "fired");

                  if (ch == EOF)
                  printf ("after fgetc 2, ch = EOF feof = %d ferror = %dn",
                  feof (fp), ferror (fp));
                  else
                  printf ("after fgetc 2, ch = '%c' feof = %d ferror = %dn",
                  ch, feof (fp), ferror (fp));

                  return 0;
                  }


                  On all three of Linux with glibc 2.27, NetBSD 7.1.2, and FreeBSD 11.2-RELEASE-p4 (which is all of the Unixes I can get at at the moment), this program prints



                  before fgetc 1, feof = 0 ferror = 0
                  after fgetc 1, ch = EOF feof = 0 ferror = 1
                  after fgetc 2, alarm did not fire
                  after fgetc 2, ch = 'x' feof = 0 ferror = 1


                  consistent with John Bollinger's observation that




                  the case of most interest, is in fact allowed:



                  1  0   1   Normal reading of valid data with error indicator set!



                  I would particularly like to know what this program prints when run on alternative Linux-based C libraries (e.g. musl, bionic); Unixes which are not Linux nor are they BSD-phylum; and Windows. If you've got anything even more exotic please try that too. I'm marking this post community wiki; please edit it to add test results.







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  answered Nov 19 at 1:05


























                  community wiki





                  zwol































                       

                      draft saved


                      draft discarded



















































                       


                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53272650%2fhow-a-stream-error-indicator-affects-following-input-code%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      mysqli_query(): Empty query in /home/lucindabrummitt/public_html/blog/wp-includes/wp-db.php on line 1924

                      How to change which sound is reproduced for terminal bell?

                      Can I use Tabulator js library in my java Spring + Thymeleaf project?