While (( c = getc(file)) != EOF) loop won’t stop executing

The return value from getc() and its relatives is an int, not a char.

If you assign the result of getc() to a char, one of two things happens when it returns EOF:

  • If plain char is unsigned, then EOF is converted to 0xFF, and 0xFF != EOF, so the loop never terminates.
  • If plain char is signed, then EOF is equivalent to a valid character (in the 8859-1 code set, that’s ÿ, y-umlaut, U+00FF, LATIN SMALL LETTER Y WITH DIAERESIS), and your loop may terminate early.

Given the problem you face, we can tentatively guess you have plain char as an unsigned type.

The reason that getc() et al return an int is that they have to return every possible value that can fit in a char and also a distinct value, EOF. In the C standard, it says:

ISO/IEC 9899:2011 §7.21.7.1 The fgetc() function

int fgetc(FILE *stream);

If the end-of-file indicator for the input stream pointed to by stream is not set and a
next character is present, the fgetc function obtains that character as an unsigned char converted to an int

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.

Similar wording applies to the getc() function and the getchar() function: they are defined to behave like the fgetc() function except that if getc() is implemented as a macro, it may take liberties with the file stream argument that are not normally granted to standard macros — specifically, the stream argument expression may be evaluated more than once, so calling getc() with side-effects (getc(fp++)) is very silly (but change to fgetc() and it would be safe, but still eccentric).


In your loop, you could use:

int c;

while ((c = getc(message)) != EOF) {
    keep[0] = c;

This preserves the assignment to keep[0]; I’m not sure you truly need it.

You should be checking the other calls to fgets(), getc(), fread() to make sure you are getting what you expect as input. Especially on input, you cannot really afford to skip those checks. Sooner, rather than later, something will go wrong and if you aren’t religiously checking the return statuses, your code is likely to crash, or simply ‘go wrong’.

Leave a Comment