为什么 fscanf(...) != 0 做的事情与 fscanf(...) == 1 不一样?

Why does fscanf(...) != 0 not do the same thing as fscanf(...) == 1?

我有一个非常简单的 C 程序:

#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);
    }
}

它工作得很好,一次从文件中读取一个字符。但是,如果我将 while 循环的条件更改为 while (fscanf(f, "%c", &c) != 0),程序似乎会陷入打印某些空白字符的无限循环。我查看了程序集,除了一条指令外,它们完全相同:

== 1 version

...
  40068a:       be 5d 07 40 00          mov    [=11=]x40075d,%esi
  40068f:       48 89 c7                mov    %rax,%rdi
  400692:       b8 00 00 00 00          mov    [=11=]x0,%eax
  400697:       e8 94 fe ff ff          callq  400530 <__isoc99_fscanf@plt>
  40069c:       83 f8 01                cmp    [=11=]x1,%eax
  40069f:       74 c9                   je     40066a <main+0x24>
  4006a1:       b8 00 00 00 00          mov    [=11=]x0,%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    [=12=]x40075d,%esi
  40068f:       48 89 c7                mov    %rax,%rdi
  400692:       b8 00 00 00 00          mov    [=12=]x0,%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    [=12=]x0,%eax
  4006a5:       c9                      leaveq 
  4006a6:       c3                      retq   
  4006a7:       66 0f 1f 84 00 00 00    nopw   0x0(%rax,%rax,1)

唯一的区别是 testcmp。这是我阅读汇编的知识,我看不出有什么不同。那么是什么导致了行为上的差异呢?

因为 fscanf returns EOF 如果在读取尝试之前到达文件末尾(即在这种情况下最后一次成功的 fscanf),则定义常量,而不是零。通常EOF等于-1,所以第二个版本变成死循环。

逻辑上两者不等价。

第一个条件只有当fscanf returns 1时才成立,即匹配到1个模式

如果 fscanf returns 是 0 以外的任何值,则第二个条件为真。因此,例如 return 值 2 将留在循环中。这不会被 returned,因为只有一种模式,但可能被 returned 的是 -1,当你点击 eof 时它会被 returned。届时,任何未来的调用都将继续到 return -1,因此你有一个无限循环。