提问人:Ana Nimbus 提问时间:9/5/2020 更新时间:9/5/2020 访问量:84
保证 getchar 收到换行符或 EOF(最终)?
Guarantee that getchar receives newline or EOF (eventually)?
问:
我想从以下情况之一开始阅读字符:stdin
- 遇到行尾标记(在我看来是正常情况),
- 这种情况发生,或
EOF
- 发生错误。
我如何保证上述事件之一最终会发生?换句话说,我如何保证最终将返回 or ,前提是没有发生错误(就 而言)?getchar
\n
EOF
ferror(stdin)
// (How) can we guarantee that the LABEL'ed statement will be reached?
int done = 0;
while (!0) if (
(c = getchar()) == EOF || ferror(stdin) || c == '\n') break;
LABEL: done = !0;
如果连接到始终提供除 以外的字符的设备,则不会发生上述任何情况。答案似乎与设备的属性有关。在哪里可以找到这些详细信息(也许在编译器、设备固件或设备硬件的配置中)?stdin
'\n'
特别是,我想知道键盘输入是否保证由行尾标记或文件末尾条件终止。同样,对于存储在光盘/ SSD上的文件。
典型用例:用户在键盘上输入文本。程序读取前几个字符并丢弃所有剩余字符,直到行尾标记或文件末尾(因为某些缓冲区已满,或者之后一切都是注释等)。
我正在使用 C89,但我很好奇答案是否取决于使用哪种 C 标准。
答:
你不能。
假设我运行你的程序,然后我在键盘的“X”键上放了一个重物,然后去夏威夷度假。在去那里的路上,我被闪电击中而死。
除了“x”之外,永远不会有任何输入。
或者,我可能会决定输入《白鲸》的完整故事,而不按回车键。这可能需要几天时间。你的程序应该等多久才能决定我可能永远打不完?
你希望它做什么?
评论
\n
keydown time > vacation duration
看看评论中的所有讨论,似乎你找错了地方:
这不是键盘驱动程序或包装的问题。stdin
这也不是你使用什么编程语言的问题。
这与软件中输入的目的有关。
基本上,作为程序员,你要知道你想要或需要多少输入,然后决定何时停止读取输入,即使有效的输入仍然可用。
请注意,不仅有些设备可以在不触发 EOF 或行尾条件的情况下永久发送输入,而且有些程序可以永远愉快地读取输入。
这是设计使然。
常见示例可以在 POSIX 风格的 OS(如 Linux)命令行工具中找到。 下面是一个简单的示例:
cat /dev/urandom | hexdump
只要您的计算机正在运行,这将打印随机数,或者直到您点击Ctrl+C
虽然当没有更多要打印的东西(EOF或任何读取错误)时会停止工作,但它并不期望这样的结束,所以除非你正在使用的实现中有一个错误,否则它应该永远快乐地运行。cat
所以真正的问题是: 您的程序何时需要停止读取字符,为什么?
如果 stdin 连接到始终提供除“\n”以外的字符的设备,则不会出现上述任何情况。
例如,设备。是的,stdin 可以连接到从不提供换行符或到达 EOF 的设备,并且预计不会报告错误情况。/dev/zero
答案似乎与设备的属性有关。
确实如此。
在哪里可以找到这些详细信息(也许在编译器、设备固件或设备硬件的配置中)?
通常,这是设备驱动程序的问题。在某些情况下(例如示例),无论如何,这就是全部。通常,驱动程序会执行对底层硬件有意义的操作,但原则上,它们不必执行。/dev/zero
特别是,我想知道键盘输入是否保证由行尾标记或文件末尾条件终止。
不。一般来说,当且仅当按下 <enter> 键时,终端设备才会发送行尾标记。如果终端断开连接(但程序继续),或者如果用户明确导致发送文件结束条件(例如,在 Linux 或 Mac 上键入 <-<D>,在 Windows 上键入 <-<Z>),则可能会发出文件结束条件的信号。这些事件实际上都不需要在任何给定的程序运行中发生,而后者不这样做是很常见的。
同样,对于存储在光盘/ SSD上的文件。
通常,您可以依靠从普通文件中读取的数据来包含文件本身中存在的换行符。如果文件以文本模式打开,则特定于系统的文本行终止符也将转换为换行符(如果不同)。文件不必包含其中任何一个,因此从常规文件中读取的程序可能永远不会看到换行符。
当文件位置等于或超过文件数据的 and 时,尝试读取时,您可以依赖 EOF 发出信号。
典型用例:用户在键盘上输入文本。程序读取前几个字符并丢弃所有剩余字符,直到行尾标记或文件末尾(因为某些缓冲区已满,或者之后一切都是注释等)。
我觉得你太努力了。
在某些情况下,读到行尾可能是一件合理的事情。如果程序旨在支持交互式使用,则期望最终达到换行符是合理的。但是,试图确保无效数据无法馈送到您的程序是一个失败的原因。你的目标应该是接受尽可能广泛的输入,并在出现其他输入时优雅地失败。
如果您需要以逐行模式读取输入,那么请务必这样做,并记录您这样做。如果只有每行的前 n 个字符对程序很重要,那么也要记录下来。然后,如果当用户将其输入连接到他们而不是您时,您的程序永远不会终止。/dev/zero
另一方面,尽量避免放置任意限制,尤其是对事物的大小。如果对某物的大小没有自然限制,那么你引入的人为限制就足够了。
评论
while true; do printf x; done | ./yourprogram
stdin