【问题标题】:Why does fscanf(...) != 0 not do the same thing as fscanf(...) == 1?为什么 fscanf(...) != 0 与 fscanf(...) == 1 不一样?
【发布时间】:2021-01-11 06:06:23
【问题描述】:

我有一个非常简单的 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", &amp;c) != 0),程序似乎会陷入打印一些空白字符的无限循环中。我查看了程序集,除了一条指令外,它们是相同的:

== 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)

唯一的区别是testcmp。就我对阅读汇编的了解而言,我看不出有什么区别。那么导致行为差异的原因是什么?

【问题讨论】:

  • 也许fscanf 也可能返回EOF(可能是负数)
  • 与特定的非零值比较应该不同于与零比较。
  • 想一想,fscanf()的可能返回值是多少?在==1 的情况下会发生什么,在!=0 的情况下会发生什么你可以期待的所有可能的返回值。
  • @IronMan EOF 必须为负数,根据 7.21 Input/output <stdio.h> paragraph 3: "... EOF 扩展为一个整数常量表达式, int 类型和负值 ..."
  • 好点,谢谢@AndrewHenle!

标签: c io scanf


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    从逻辑上讲,两者并不等价。

    第一个条件只有在 fscanf 返回 1 时才成立,这意味着匹配了 1 个模式。

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

    【讨论】:

    • EOF 不一定是 -1,尽管它是负数。并且针对任何输入失败(例如管道损坏)返回,而不仅仅是文件结尾。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-04
    • 1970-01-01
    • 1970-01-01
    • 2022-01-01
    • 1970-01-01
    相关资源
    最近更新 更多