scanf 如何确定是否阻塞?

6
当我使用命令行中的MyProgram < cl.txt 命令将文件重定向到stdin时,scanf不会等待我按Enter键。
但是当我在程序中使用scanf而没有这样做时,它会阻塞直到按下Enter键。
它是如何确定的呢?它是否一直读取流直到遇到\n?还是真的等我按键?
当我不写任何内容并按Enter键时,它也不停止阻塞并继续询问。我真的很困惑。

1
使用 MyProgram < cl.txt,您将没有机会手动输入任何内容。输入文件包含您的所有输入。 - Egor Skriptunoff
3个回答

8
它会一直读取流,直到遇到 '\n' 吗?通常,stdin 处于行缓冲模式(_IOLBF,详见setvbuf)。每当缓冲区为空时,stdin 会等待输入一个完整的新行,也就是等待您按下回车键并将 \n 插入缓冲区。如下所示:

在输入时,当请求输入操作且缓冲区为空时,缓冲区会填充到下一个换行符。

注意:控制台(终端)往往会自行实现缓冲,直到您按下回车键之前不会将任何数据发送到流中-这使您可以在发送数据到应用程序之前编辑数据(例如使用删除和退格键)。因此,即使在 stdin 端没有缓冲(例如当您执行 setvbuf(stdin, NULL, _IONBF, 0) 时),scanf 仍可能会等待您按下回车键。


7

scanf 只是从其输入流中读取数据。 如果输入流是一个管道,而该管道的另一端与 tty 相关联(如果您通过键盘交互式输入数据通常情况下就是这种情况),则 scanf 会在读取完成格式字符串(或无法匹配)的数据后立即返回。然而,tty 如果处于 cooked 模式(这是默认设置,除非您做出努力将 tty 切换到 raw 模式,否则应该假定它正在处理您键入的内容),在您按下回车之前将不会向管道写入任何数据。

换句话说,造成阻塞的不是您的 scanf。(好吧,它确实会阻塞,但它不是体验延迟的原因。)相反,tty 驱动程序正在等待你按回车键,然后才将数据传递给程序。


当我按下回车键而没有输入任何内容时,是操作系统忽略该输入还是scanf本身忽略了? - Insignificant Person
@InsignificantPerson 我认为scanf不会忽略输入,它只是需要更多的输入,由于输入缓冲区中没有更多的数据,stdin会阻塞直到数据到达。 - Suma
1
@InsignificantPerson 这取决于格式字符串,但通常格式字符串是这样的,scanf会忽略前导空格。在这种情况下,您孤立的换行符被读取(但被忽略),因为scanf继续寻找要匹配格式字符串的数据。 - William Pursell

3
当您调用scanf时,它立即等待输入。在第一个示例中,输入以“cl.txt”形式提供。在第二个示例中,除非您按键,否则不会提供任何输入。同步IO将阻止其执行线程,直到它接收到输入。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接