【问题标题】:Using EOF in the middle of an input line?在输入行中间使用EOF?
【发布时间】:2017-03-12 21:20:58
【问题描述】:

对于我的程序,我有一个标准输出提示

>

然后我的程序从标准输入读取。如果未达到 EOF,则提示循环。我注意到如果我输入了一些东西,例如:

> bee

当我按一次 CTRL-D 时,什么也没有发生。当我再次按 CTRL-D 时,我的提示再次出现。只有当我第三次按下它时,我的程序才会因 EOF 而终止。这是否意味着我的代码有问题?还是这是正常行为?

这是我的代码的简化版本:

(fopen used)
(print prompt)
while((fgets(tester, 1026, input)) != NULL) {
   if(there is a # in tester) {
     (print prompt)        
     continue;
   }
}

【问题讨论】:

  • 哪个代码有问题?
  • Ctrl+D (Linux) 或 Ctrl+Z (Windows) 必须是 newline 之后的第一个按键。但是,我仍然注意到我无法解决的类似问题。
  • 这个伪代码混合不编译,唯一似乎解析的部分有括号不匹配。请发布一个最小的完整示例。
  • 键盘状态和序列在您的 C 程序“外部”。因此,用于表示stdin 的文件结束的任何内容都是特定于平台的。如果不指定您的计算机/操作系统等,可以考虑这是否是正常行为,但明确的答案需要来自 OP 的更多信息。

标签: c io


【解决方案1】:

在 unix 终端中,CTRL-D 只是立即发送终端输入缓冲区中的所有待处理字节。


背景:

通常,当您在终端中输入内容时,该内容是行缓冲的,因此您可以继续编辑一行直到您满意为止,然后通过输入换行符(或 CTRL-D)将其发送到正在运行的进程, 区别只是 CTRL-D 没有在末尾添加换行符)。

现在,进程通过检查read() 调用是否返回任何内容来检测输入流的结束。因此,如果您在一个空的输入缓冲区上按 CTRL-D,read() 调用将返回任何内容,并且该进程认为“没有更多字节从该流中流出,我最好不要再试一次”。 Afaik,没有其他方法可以检查输入流的结尾,因此所有在stdin 上识别EOF 的程序都会直接或通过标准C 库执行此操作。后者是你打电话给fgets()时所做的。


您的情况:

  1. 第一个 CTRL-D 只是将三个字符“bee”发送到您的进程。您的fgets() 调用中的read() 调用返回这三个字符,并且您的fgets() 实现检查换行符。由于它没有找到任何字符,并且它自己的输出缓冲区尚未满,它会立即通过另一个read() 调用来获取更多字符。

  2. 第二个 CTRL-D 没有发送任何内容,因为自上次 CTRL-D 以来您没有输入任何其他字符。 write() 调用返回没有输出,fgets() 看到它收到零个字符并将其称为 EOF 条件。所以它会返回(大部分是缓冲的)字符串 "bee" 给你。

    您的程序可能会检查该字符串是否包含# 字符。但是直到fgets() 调用返回NULL(没有break 语句可以初步离开循环),它的循环才能终止。

  3. 第三个 CTRL-D 再次向您的进程发送零字节。这会导致第二个fgets() 调用的第一个read() 调用返回零字节(循环将在第一次迭代成功后重新进入)。 fgets() 实现看到空结果,由于它发现它还没有收到任何字节,它返回NULL。您的循环条件看到NULL 并终止循环,这反过来又导致您的main() 返回并退出进程。


TL;DR:

是的,这完全是意料之中的行为,尽管它看起来相当违反直觉。这就是 UNIX:它是 KISS,不一定是直观的。

【讨论】:

    猜你喜欢
    • 2015-03-29
    • 1970-01-01
    • 2015-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多