How a stream error indicator affects following input code?












3














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 '18 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 '18 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 '18 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 '18 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 '18 at 17:35


















3














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 '18 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 '18 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 '18 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 '18 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 '18 at 17:35
















3












3








3


2





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 '18 at 2:16

























asked Nov 13 '18 at 1:53









chux

80.5k870147




80.5k870147












  • Are you looking for a standards-based answer (perhaps language-lawyer), or a practical answer?
    – Nominal Animal
    Nov 13 '18 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 '18 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 '18 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 '18 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 '18 at 17:35




















  • Are you looking for a standards-based answer (perhaps language-lawyer), or a practical answer?
    – Nominal Animal
    Nov 13 '18 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 '18 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 '18 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 '18 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 '18 at 17:35


















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




Are you looking for a standards-based answer (perhaps language-lawyer), or a practical answer?
– Nominal Animal
Nov 13 '18 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 '18 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 '18 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 '18 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 '18 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 '18 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 '18 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 '18 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 '18 at 17:35














4 Answers
4






active

oldest

votes


















2















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 '18 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 '18 at 14:14



















1














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





























    1














    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 '18 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 '18 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 '18 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 '18 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 '18 at 20:58





















    1














    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 of the Unixes I can get at at the moment, this program's output is 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.



    The test program should be acceptable to any C89-compliant compiler for an environment where unistd.h exists and signal.h defines sigaction, except for one use of the C11 _Noreturn keyword which is only to squelch warnings. If your compiler complains about _Noreturn, compile with -D_Noreturn=; the results will not be affected. If you don't have unistd.h, the test program will not do anything meaningful in your environment. If you don't have sigaction you may be able to adapt the program to use alternative interfaces, but you need to persuade SIGALRM to interrupt a blocking read somehow.



    Results



    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


    ("normal reading of valid data with error indicator set")




    • Linux with glibc 2.27

    • NetBSD 7.1.2

    • FreeBSD 11.2-RELEASE-p4

    • macOS 10.14, clang-1000.10.44.2

    • macOS 10.14, gcc 8.2.0 (Homebrew)


    .



    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 = EOF feof = 0 ferror = 1


    ("sticky error" behavior: fgetc(fp) immediately returns EOF without calling read when ferror(fp) is true on entry)




    • Plan 9 (compiler does not recognize _Noreturn)


    .






    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',
      autoActivateHeartbeat: false,
      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









      2















      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 '18 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 '18 at 14:14
















      2















      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 '18 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 '18 at 14:14














      2












      2








      2







      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 '18 at 18:30

























      answered Nov 13 '18 at 6:14









      John Bollinger

      78.6k73974




      78.6k73974












      • 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 '18 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 '18 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 '18 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 '18 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 '18 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 '18 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 '18 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 '18 at 14:14













      1














      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


























        1














        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
























          1












          1








          1






          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 '18 at 4:22









          R..

          155k26257561




          155k26257561























              1














              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 '18 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 '18 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 '18 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 '18 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 '18 at 20:58


















              1














              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 '18 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 '18 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 '18 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 '18 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 '18 at 20:58
















              1












              1








              1






              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 '18 at 16:04









              Nominal Animal

              29k33359




              29k33359












              • 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 '18 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 '18 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 '18 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 '18 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 '18 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 '18 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 '18 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 '18 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 '18 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 '18 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 '18 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 '18 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 '18 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 '18 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 '18 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 '18 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 '18 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 '18 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 '18 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 '18 at 20:58













              1














              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 of the Unixes I can get at at the moment, this program's output is 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.



              The test program should be acceptable to any C89-compliant compiler for an environment where unistd.h exists and signal.h defines sigaction, except for one use of the C11 _Noreturn keyword which is only to squelch warnings. If your compiler complains about _Noreturn, compile with -D_Noreturn=; the results will not be affected. If you don't have unistd.h, the test program will not do anything meaningful in your environment. If you don't have sigaction you may be able to adapt the program to use alternative interfaces, but you need to persuade SIGALRM to interrupt a blocking read somehow.



              Results



              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


              ("normal reading of valid data with error indicator set")




              • Linux with glibc 2.27

              • NetBSD 7.1.2

              • FreeBSD 11.2-RELEASE-p4

              • macOS 10.14, clang-1000.10.44.2

              • macOS 10.14, gcc 8.2.0 (Homebrew)


              .



              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 = EOF feof = 0 ferror = 1


              ("sticky error" behavior: fgetc(fp) immediately returns EOF without calling read when ferror(fp) is true on entry)




              • Plan 9 (compiler does not recognize _Noreturn)


              .






              share|improve this answer




























                1














                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 of the Unixes I can get at at the moment, this program's output is 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.



                The test program should be acceptable to any C89-compliant compiler for an environment where unistd.h exists and signal.h defines sigaction, except for one use of the C11 _Noreturn keyword which is only to squelch warnings. If your compiler complains about _Noreturn, compile with -D_Noreturn=; the results will not be affected. If you don't have unistd.h, the test program will not do anything meaningful in your environment. If you don't have sigaction you may be able to adapt the program to use alternative interfaces, but you need to persuade SIGALRM to interrupt a blocking read somehow.



                Results



                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


                ("normal reading of valid data with error indicator set")




                • Linux with glibc 2.27

                • NetBSD 7.1.2

                • FreeBSD 11.2-RELEASE-p4

                • macOS 10.14, clang-1000.10.44.2

                • macOS 10.14, gcc 8.2.0 (Homebrew)


                .



                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 = EOF feof = 0 ferror = 1


                ("sticky error" behavior: fgetc(fp) immediately returns EOF without calling read when ferror(fp) is true on entry)




                • Plan 9 (compiler does not recognize _Noreturn)


                .






                share|improve this answer


























                  1












                  1








                  1






                  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 of the Unixes I can get at at the moment, this program's output is 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.



                  The test program should be acceptable to any C89-compliant compiler for an environment where unistd.h exists and signal.h defines sigaction, except for one use of the C11 _Noreturn keyword which is only to squelch warnings. If your compiler complains about _Noreturn, compile with -D_Noreturn=; the results will not be affected. If you don't have unistd.h, the test program will not do anything meaningful in your environment. If you don't have sigaction you may be able to adapt the program to use alternative interfaces, but you need to persuade SIGALRM to interrupt a blocking read somehow.



                  Results



                  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


                  ("normal reading of valid data with error indicator set")




                  • Linux with glibc 2.27

                  • NetBSD 7.1.2

                  • FreeBSD 11.2-RELEASE-p4

                  • macOS 10.14, clang-1000.10.44.2

                  • macOS 10.14, gcc 8.2.0 (Homebrew)


                  .



                  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 = EOF feof = 0 ferror = 1


                  ("sticky error" behavior: fgetc(fp) immediately returns EOF without calling read when ferror(fp) is true on entry)




                  • Plan 9 (compiler does not recognize _Noreturn)


                  .






                  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 of the Unixes I can get at at the moment, this program's output is 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.



                  The test program should be acceptable to any C89-compliant compiler for an environment where unistd.h exists and signal.h defines sigaction, except for one use of the C11 _Noreturn keyword which is only to squelch warnings. If your compiler complains about _Noreturn, compile with -D_Noreturn=; the results will not be affected. If you don't have unistd.h, the test program will not do anything meaningful in your environment. If you don't have sigaction you may be able to adapt the program to use alternative interfaces, but you need to persuade SIGALRM to interrupt a blocking read somehow.



                  Results



                  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


                  ("normal reading of valid data with error indicator set")




                  • Linux with glibc 2.27

                  • NetBSD 7.1.2

                  • FreeBSD 11.2-RELEASE-p4

                  • macOS 10.14, clang-1000.10.44.2

                  • macOS 10.14, gcc 8.2.0 (Homebrew)


                  .



                  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 = EOF feof = 0 ferror = 1


                  ("sticky error" behavior: fgetc(fp) immediately returns EOF without calling read when ferror(fp) is true on entry)




                  • Plan 9 (compiler does not recognize _Noreturn)


                  .







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Nov 26 '18 at 19:10


























                  community wiki





                  4 revs, 3 users 94%
                  zwol































                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.





                      Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                      Please pay close attention to the following guidance:


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.




                      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

                      Xamarin.iOS Cant Deploy on Iphone

                      Glorious Revolution

                      Dulmage-Mendelsohn matrix decomposition in Python