对于我的程序,我有stdout的提示
>
然后我的程序从stdin读取。如果尚未达到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;
}
}
答案 0 :(得分:0)
在unix终端中,CTRL-D不会多于或少于立即发送终端输入缓冲区中待处理的所有字节。
<强>背景强>
通常情况下,当您在终端中输入内容时,这些内容是行缓冲的,因此您可以继续编辑一行直到您对它满意为止,然后通过输入换行符(或CTRL-D)将其发送到正在运行的进程中,区别仅在于CTRL-D最后没有添加换行符。)
现在,进程通过检查read()
调用是否返回任何内容来检测输入流的结束。因此,如果你在一个空的输入缓冲区上按CTRL-D,read()
调用什么都不返回,并且进程认为“没有更多的字节来自这个流,我最好不要再试一次”。 Afaik,没有其他方法可以检查输入流的结束,因此所有识别EOF
stdin
的程序都可以直接或通过标准C库执行此操作。后者就是你打电话给fgets()
时所做的。
您的情况:
第一个CTRL-D只是将三个字符“bee”发送到您的进程。 read()
调用中的fgets()
调用会返回这三个字符,而您的fgets()
实现会检查换行符。由于它没有找到,并且由于它自己的输出缓冲区尚未填满,它会立即通过另一个read()
调用来获取更多字符。
第二个CTRL-D没有发送任何内容,因为自上次CTRL-D以来您没有输入任何其他字符。 write()
调用返回时没有输出,fgets()
看到它收到零个字符并将其称为EOF条件。所以它返回(主要是缓冲的)字符串"bee"
给你。
您的程序可能会检查该字符串是否包含#
个字符。但是在fgets()
调用返回NULL
之前,它的循环无法终止(没有break
语句可以初步离开循环)。
第三个CTRL-D再次向您的进程发送零字节。这导致第二次read()
调用的第一次fgets()
调用返回零字节(在第一次迭代成功后,循环即将重新进入)。 fgets()
实现看到空结果,并且由于它发现它还没有收到任何字节,它返回NULL
。您的循环条件会看到NULL
并终止循环,从而导致您的main()
返回,退出流程。
<强> TL; DR:强>
是的,这是完全预期的行为,即使它看起来相当反直觉。这是UNIX:它是KISS,不一定是直观的。