Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is getc() defined after it has returned EOF?

Tags:

c

io

I use getc(); in a C excercise, and after looking back on the program I noticed something weird. I assumed that the file given on the command line arguments contains at least one byte. (It calls getc(); twice in a row without checking for EOF. After trying it on an empty file it still worked smoothly. My question is: is the behaviour of getc(); on a file pointer that's been exhausted (EOF has been reached and not rewinded) undefined or will it always continue to return EOF?

I think I could expand this question to all the I/O functions in the C STL, please clarify this in your answer too.

Here is the code for the program. The program is supposed to strip a C/C++ source file from all comments (and it works perfectly).

#include <stdio.h>

int main(int argc, char *argv[]) {
    int state = 0; // state: 0 = normal, 1 = in string, 2 = in comment, 3 = in block comment
    int ignchar = 0; // number of characters to ignore
    int cur, next; // current character and next one
    FILE *fp; // input file

    if (argc == 1) {
        fprintf(stderr, "Usage: %s file.c\n", argv[0]);
        return 1;
    }

    if ((fp = fopen(argv[1], "r")) == NULL) {
        fprintf(stderr, "Error opening file.\n");
        return 2;
    }

    cur = getc(fp); // initialise cur, assumes that the file contains at least one byte
    while ((next = getc(fp)) != EOF) {
        switch (next) {
            case '/':
                if (!state && cur == '/') {
                    state = 2; // start of comment
                    ignchar = 2; // don't print this nor next char (//)
                } else if (state == 3 && cur == '*') {
                    state = 0; // end of block comment
                    ignchar = 2; // don't print this nor next char (*/)
                }
                break;
            case '*':
                if (!state && cur == '/') {
                    state = 3; // start of block comment
                    ignchar = 2; // don't print this nor next char (/*)
                }
                break;
            case '\n':
                if (state == 2) {
                    state = 0;
                    ignchar = 1; // don't print the current char (cur is still in comment)
                }
                break;
            case '"':
                if (state == 0) {
                    state = 1;
                } else if (state == 1) {
                    state = 0;
                }
        }

        if (state <= 1 && !ignchar) putchar(cur);
        if (ignchar) ignchar--;
        cur = next;
    }

    return 0;
}
like image 922
orlp Avatar asked Feb 26 '23 08:02

orlp


1 Answers

Stdio files keep an "eof" flag that's set the first time end-of-file is reached and can only be reset by calling clearerr or performing a successful fseek or rewind. Thus, once getc returns EOF once, it will keep returning EOF, even if new data becomes available, unless you use one of the aforementioned methods for clearing the eof flag.

Some non-conformant implementations may immediately make new data available. This behavior is harmful and can break conformant applications.

like image 105
R.. GitHub STOP HELPING ICE Avatar answered Mar 08 '23 16:03

R.. GitHub STOP HELPING ICE