为什么 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)
唯一的区别是 test
与 cmp
。这是我阅读汇编的知识,我看不出有什么不同。那么是什么导致了行为上的差异呢?
因为 fscanf
returns EOF
如果在读取尝试之前到达文件末尾(即在这种情况下最后一次成功的 fscanf),则定义常量,而不是零。通常EOF
等于-1
,所以第二个版本变成死循环。
逻辑上两者不等价。
第一个条件只有当fscanf returns 1时才成立,即匹配到1个模式
如果 fscanf returns 是 0 以外的任何值,则第二个条件为真。因此,例如 return 值 2 将留在循环中。这不会被 returned,因为只有一种模式,但可能被 returned 的是 -1,当你点击 eof 时它会被 returned。届时,任何未来的调用都将继续到 return -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)
唯一的区别是 test
与 cmp
。这是我阅读汇编的知识,我看不出有什么不同。那么是什么导致了行为上的差异呢?
因为 fscanf
returns EOF
如果在读取尝试之前到达文件末尾(即在这种情况下最后一次成功的 fscanf),则定义常量,而不是零。通常EOF
等于-1
,所以第二个版本变成死循环。
逻辑上两者不等价。
第一个条件只有当fscanf returns 1时才成立,即匹配到1个模式
如果 fscanf returns 是 0 以外的任何值,则第二个条件为真。因此,例如 return 值 2 将留在循环中。这不会被 returned,因为只有一种模式,但可能被 returned 的是 -1,当你点击 eof 时它会被 returned。届时,任何未来的调用都将继续到 return -1,因此你有一个无限循环。