0
votes

I have a really simple C program:

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

int main(int argc, char** argv) {
    FILE* f = fopen("file.txt", "r");
    char c;
    while (fscanf(f, "%c", &c) == 1) {
        printf("char: %c\n", c);
    }
}

which works perfectly fine, reading one character at a time from the file. But if I change the condition on the while loop to while (fscanf(f, "%c", &c) != 0), the program appears to get stuck in an infinite loop of printing some whitespace character. I looked at the assembly, and they're identical except for a single instruction:

== 1 version

...
  40068a:       be 5d 07 40 00          mov    $0x40075d,%esi
  40068f:       48 89 c7                mov    %rax,%rdi
  400692:       b8 00 00 00 00          mov    $0x0,%eax
  400697:       e8 94 fe ff ff          callq  400530 <__isoc99_fscanf@plt>
  40069c:       83 f8 01                cmp    $0x1,%eax
  40069f:       74 c9                   je     40066a <main+0x24>
  4006a1:       b8 00 00 00 00          mov    $0x0,%eax
  4006a6:       c9                      leaveq 
  4006a7:       c3                      retq   
  4006a8:       0f 1f 84 00 00 00 00    nopl   0x0(%rax,%rax,1)
  4006af:       00 

!= 0 version

  40068a:       be 5d 07 40 00          mov    $0x40075d,%esi
  40068f:       48 89 c7                mov    %rax,%rdi
  400692:       b8 00 00 00 00          mov    $0x0,%eax
  400697:       e8 94 fe ff ff          callq  400530 <__isoc99_fscanf@plt>
  40069c:       85 c0                   test   %eax,%eax
  40069e:       75 ca                   jne    40066a <main+0x24>
  4006a0:       b8 00 00 00 00          mov    $0x0,%eax
  4006a5:       c9                      leaveq 
  4006a6:       c3                      retq   
  4006a7:       66 0f 1f 84 00 00 00    nopw   0x0(%rax,%rax,1)

And the only difference is a test versus cmp. This is as far as my knowledge of reading assembly goes, and I don't see a difference. So what causes the difference in behavior?

2
perhaps fscanf might also return EOF (which could be negative)IronMan
Comparing against a specific nonzero value ought to be different than comparing against zero.Steve Friedl
Think about it, what are the possible return values of fscanf()? What happens in case of ==1 and what in the case of !=0 at all the possible return values you can expect.12431234123412341234123
@IronMan EOF must be negative, per 7.21 Input/output <stdio.h> paragraph 3: "... EOF which expands to an integer constant expression, with type int and a negative value ..."Andrew Henle
Good point, thanks @AndrewHenle!IronMan

2 Answers

4
votes

Because fscanf returns EOF define constant if the end of file is reached before read attempt (i.e. last successful fscanf in this case), not zero. Usually EOF equals to -1, that's why the second version turns into an infinite loop.

2
votes

Logically the two are not equivalent.

The first condition is true only when fscanf returns 1, which means 1 pattern was matched.

The second condition is true if fscanf returns any value other than 0. So a return value of 2 for example would stay in the loop. That won't be returned because there is only one pattern, but what could be returned is -1, and it will be returned when you hit eof. At that point any future calls will continue to return -1, so you have an infinite loop.