c - 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
解决方案
MacOS 行为是正确的。根据C 标准 §7.21.7.1/3(fgetc
库函数),文件结束指示是粘性的;一旦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)遵循上面引用的标准。
推荐阅读
- bash - 在 bash 脚本中的一位数字/文本前面添加 0
- github - 如何防止原始 github 令牌过期
- javascript - 如何在 Angular 6 中发送 ajax 请求?
- python - 在打印语句中调用对象名称。我做对了吗?
- git - 从 `git rev-list` 命令输出中排除 `commit ...` 行
- c - 在扩展 asm 输出参数中使用“+”修饰符时输入参数索引?
- java - 比类访问修饰符限制更少的成员访问修饰符有什么用?
- javascript - 如何一次扫描一个条形码?[反应原生相机]
- javascript - 调用脚本时 Javascript 代码返回“未找到”
- android - 如何在最近的应用程序中使屏幕空白但允许屏幕截图