3

I was attempting to read a file as such:

char c;
while ((c = fgetc(fp) != EOF)) { ... }

And was not stepping into the loop. Why doesn't this code work?

I realized the error was failing to place the wrapping parenthesis before the not equals comparison to EOF, as such:

char c;
while ((c = fgetc(fp)) != EOF) { ... }

However, I don't understand why the first conditional doesn't work. I tested it with printf("%d", c = fgetc(fp) != EOF), and that returns 1. So the issue must be something to do with the conditional being wrapped inside of (...) parenthesis, which would seem to make it be evaluating to while ( (1) ).

I bet I am misunderstanding RE: the operator association order, but do not know for certain the root of the error here.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
socrates
  • 327
  • 2
  • 11
  • I’m not sure what would explain the difference with `printf`, but `char` is the wrong type for `c` either way; `fgetc` returns an `int`, because `EOF` shouldn’t conflict with any `char`. – Ry- Aug 18 '20 at 20:55
  • 6
    It's not the double parentheses that make a difference, it's the fact that `!=` has [higher precedence](https://en.cppreference.com/w/c/language/operator_precedence) than `=`. – GSerg Aug 18 '20 at 20:55
  • An assignment expression has the value of the left operand after the assignment, which means that c = fgetc(fp) will be whatever value that ascii character happens to have. Try to do the assignment outside of the condition. – Galan Lucian Aug 18 '20 at 20:55
  • 2
    I'm unable to reproduce this. It steps into the loop for me, with `c=1`, until it hits EOF at which point it exits with `c=0`. How did you determine that the loop wasn't entered? – that other guy Aug 18 '20 at 20:56
  • @thatotherguy It is my mistake. I was printing the character inside the loop to show what was being read. However, I was printing it as a `char`, when in fact it was evaluating to an `int`, as mentioned. So I suppose I was seeing garbage output or nothing at all. Not a great way to test, admittedly. – socrates Aug 19 '20 at 16:49

1 Answers1

2

The condition expression depends on the precedence of operations.

In fact in this while loop

while ((c = fgetc(fp) != EOF)) { ... } 

you may remove a pair of external parentheses like

while ( c = fgetc(fp) != EOF ) { ... } 

because they do not change the semantic of the condition.

Now according to the operator precedence this loop looks like

while ( c = ( fgetc(fp) != EOF ) ) { ... } 

The expression in the inner parentheses ( fgetc(fp) != EOF ) is evaluated either to integer 0 or 1 as a logical expression.

So as result you will get either

while ( c = 1 ) { ... }

if the expression ( fgetc(fp) != EOF ) evaluates to the logical true or

while ( c = 0 ) { ... }

if the expression evaluates to the logical false.

Pay attention to that the variable c shall be declared as having the type int because it is the return type of the function fgetc that can return the value EOF.

int c;
while ( ( c = fgetc(fp) ) != EOF ) { ... }

Otherwise you will compare an object of the type char and an object of the type int that is defined as the macro EOF.

However in general the type char can behave as the type unsigned char (depending on a compiler option or by default) and in this case due to the integer promotion an object of the type char (that stores a non-negative value) will never be equal to EOF that is defined usually like -1. (or like some other negative value).

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335