【问题标题】:How does scanf determine whether to block?scanf 如何判断是否阻塞?
【发布时间】:2015-05-23 06:19:39
【问题描述】:

当我从命令行使用MyProgram < cl.txt 命令将文件重定向到stdin 时,scanfs 不会等待我按 Enter。

但是当我在我的程序中使用scanf 而不这样做时,它会阻塞直到按下回车键。

它究竟是如何确定的?它会一直读取流直到遇到\n?还是真的等我按一个键?

当我不写任何东西并按 Enter 时,它也不会停止阻塞并继续询问。我真的很困惑。

【问题讨论】:

  • 使用MyProgram < cl.txt,您没有机会手动输入内容。输入文件包含您的所有输入。

标签: c scanf io-redirection


【解决方案1】:

scanf 只是从其输入流中读取。如果输入流是一个管道,并且该管道的另一端与一个 tty 相关联(如果您通过键盘上的键交互地输入数据,通常就是这种情况),scanf 将在读取数据后立即返回完成其格式字符串(或无法匹配它)。但是,如果 tty 处于熟模式(这是默认模式,除非您努力将 tty 置于原始模式,否则您应该假设它正在烹饪您键入的内容),不会将任何数据写入管道直到你按下回车键。

换句话说,阻塞的不是你的 scanf。 (嗯,它是阻塞的,但它不是所经历的延迟的根源。)相反,tty 驱动程序在将任何数据传递给您的程序之前等待您点击返回。

【讨论】:

  • 当我按下回车而不输入任何内容时,是操作系统忽略了该输入还是 scanf 本身?
  • @InsignificantPerson 我不认为 scanf 会忽略输入,它只需要更多输入,并且由于输入缓冲区中没有更多数据,stdin 会阻塞直到数据到达。
  • @InsignificantPerson 这取决于格式字符串,但通常格式字符串会使 scanf 忽略前导空格。在这种情况下,当 scanf 继续寻找与格式字符串匹配的数据时,将读取(但忽略)您的单独换行符。
【解决方案2】:

在遇到 '\n' 之前它会一直读取流吗?

通常stdin 处于行缓冲模式(_IOLBF,请参阅setvbuf)。每当缓冲区为空时,stdin 都会等待输入一个全新的行,即等到您按 Enter 并将 \n 插入缓冲区:

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

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-03-23
      • 2019-04-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-16
      • 2011-04-09
      • 2017-01-25
      相关资源
      最近更新 更多