首页 > 解决方案 > macOS 和 centos 上的 EOF 不同的结果

问题描述

我正在使用EOF跳出'while'循环,并想通过'scanf'输入一些数字。循环外的'scanf'在macos上不起作用。

我试过在macos和centos上运行这段代码。centos上的结果就是我需要的。

#include <stdio.h>
#include <stdlib.h>
int main(){
 int i;
 //ctrl+d=EOF
 while(scanf("%d",&i) != EOF){
  printf("?");
 }
 printf("\nloopend\n");
 //those 'scanf' are ignored on macos.
 scanf("%d",&i);
 scanf(" %d",&i);
 scanf("%d ",&i);
 printf("\nend\n");
}

输入(不带','):1,\n,ctrl+d

输出(centos):

1
?
loopend
//waiting for input here

输出(macos):

1
?
loopend

end
//the program ended directly

标签: cmacoscentos

解决方案


MacOS 行为是正确的。根据C 标准 §7.21.7.1/3fgetc库函数),文件结束指示是粘性的;一旦fgetc看到 EOF,它必须设置文件的文件结束指示符,这将导致后续调用返回EOF,直到文件结束指示符被清除,例如clearerr()

如果设置了流的文件结束指示符,或者如果流处于文件结束位置,则设置流的文件结束指示符并且 fgetc 函数返回 EOF。否则,fgetc 函数从 stream 指向的输入流中返回下一个字符。如果发生读取错误,则设置流的错误指示符并且 fgetc 函数返回 EOF。

由于其他输入函数,包括scanf,应该像通过重复调用来实现一样fgetc,EOF 对它们也应该是粘性的。如果您想在收到 EOF 返回后继续阅读,您应该调用clearerr()流。(或其他重置指标的东西,例如seek()。)

多年来,标准 C 库的 Gnu 实现并没有遵循标准。它只报告 EOF 一次,让下一个fgetc等待终端和管道等设备上的更多输入。该错误于 2006 年报告,最终在 2018 年 8 月发布的 v2.28 中得到修复,尽管这可能还不是 Centos 发行版的一部分。

[注意:在这个答案中有一个关于这种行为的更长的讨论,包括一个现在已经过时的抱怨(我)和一些关于这个问题的历史讨论的链接。]

无论如何,可移植代码应该调用 一直很清楚clearerr(),因为 BSD 派生的标准库实现(包括 MacOS)遵循上面引用的标准。


推荐阅读