【问题标题】:How does the data flow from input stream into the input buffer during scanf() in C?在 C 中的 scanf() 期间,数据如何从输入流流入输入缓冲区?
【发布时间】:2015-01-14 08:04:39
【问题描述】:

例如,当我执行 scanf("%s",arg); 时:终端允许我输入文本,直到遇到换行符,但它最多只能存储 arg 变量内的第一个空格字符。剩余部分保留在缓冲区中。

scanf("%c", arg); :在这种情况下,它还允许我在终端中输入文本,直到我给出一个换行符,但只有一个存储在 arg 中,其余的保留在缓冲区中。

scanf("%[^P]", arg); :在这种情况下,即使在给它一个换行符之后,我也可以在终端中输入文本,直到我点击带有“P”的行并按回车键(换行符),然后将所有内容传输到输入缓冲区。

如何确定一次从输入流中传输多少数据到输入缓冲区?

假设arg 是正确的类型。

我的理解似乎从根本上是错误的。如果有人能解释一下这些东西,我将非常感激。

【问题讨论】:

  • 这里涉及更多层。 gnome-terminal-server -> ptmx -> 内核 -> pts -> 你的进程的 read() 调用 -> libc 缓冲 -> scanf()
  • keyboard-electrical-contact -> keyboard-matrix-scanner -> usb-interface -> keyboard-driver -> gnome-terminal-server -> ... - 我可能也错过了很多 :-)

标签: c input buffer stdin scanf


【解决方案1】:

如何确定?它由格式字符串本身决定。

scanf 函数将读取项目,直到它们不再与给定的格式说明符匹配。然后它停止,将第一个“不合规”字符留在缓冲区中。

如果你的意思是“它是如何在幕后处理的?”,那是另一个问题。

我对此的第一反应是“没关系”。 ISO 标准规定了语言的工作方式,并描述了能够做到这一点的“虚拟机”。只要你遵循机器的规则,你就不必担心事情在幕后是如何发生的。

我的第二个答案可能更令人满意,但非常依赖于实现。

为了提高效率,底层软件可能不会将任何数据传递给实现,直到它有一个完整的行(尽管这当然可能是可配置的,例如为终端设置原始模式)。这意味着退格之类的东西可能更改已经输入的字符,而不是插入到流中。

它可能(例如使用 GNU readline() 库允许在传递字符之前在线进行各种真正精美的编辑。没有什么可以阻止底层软件甚至打开 vim 会话以允许您输入数据,只有在您退出时才交付它:-)

【讨论】:

  • 在我按下键盘上的回车键之前它是否开始阅读?那是我仍在向终端输入文本的过程中?在那种情况下,它如何应对按下的退格键?
  • 感谢您的回答扩展。因此,根据格式说明符,编译器(或软件)在 scanf("[^P]"..) 的情况下请求更多行。我假设一旦按下换行符,我的终端和操作系统就会传送这些行。如果我理解错了,请纠正我。
  • @aste123,是的,你是对的(在熟模式下),再说一遍,这不是 ISO C 指定的,它是在 超出 范围的情况下完成的。在原始或规范模式下,您可能会在按下一个字符后立即获得它。但这只是意味着交付给scanf,它仍然可以控制何时将最终产品还给您。
【解决方案2】:

缓冲区和原始编辑功能由操作系统提供。 如果您可以将终端设置为“原始模式”,您将看到不同的行为。

例如:在按下 Enter 之前,字符可能可供读取,尤其是在缓冲区也可以禁用的情况下。

【讨论】:

    【解决方案3】:

    我认为,它与how much 无关,而与格式说明符告诉的内容有关。

    根据C99,第 7.19.6.2 章第 2 段,(针对fscanf()

    fscanf 函数从流指向的流中读取输入,受控制 格式所指向的字符串的名称,该格式指定了可接受的输入序列以及如何 它们将被转换为赋值,使用后续参数作为指向 对象来接收转换后的输入。

    对于格式说明符,您需要参考第 12 段。

    【讨论】:

      猜你喜欢
      • 2014-09-14
      • 1970-01-01
      • 2015-01-09
      • 1970-01-01
      • 2016-01-21
      • 2015-05-23
      • 2016-01-17
      • 2016-12-23
      • 2015-12-31
      相关资源
      最近更新 更多