2
#include <stdio.h>
int main()
{
    int age;
    printf("Enter Your age: ");
    scanf("%lf", &age);
    printf("Your age is %d\n", age);
    return 0;

}

如果我们运行程序,提示将显示在终端屏幕上,即使提示末尾没有换行符。这怎么可能发生?

4

3 回答 3

1

如评论中所述,C 标准 (ISO/IEC 9899:2011) 说:

§5.1.2.3 程序执行

¶6 对一致性实现的最低要求是:

  • 对 volatile 对象的访问严格按照抽象机的规则进行评估。
  • 在程序终止时,写入文件的所有数据应与根据抽象语义执行程序所产生的结果相同。
  • 交互设备的输入和输出动态应按照 7.21.3 中的规定进行。这些要求的目的是尽快出现无缓冲或行缓冲的输出,以确保在程序等待输入之前实际出现提示消息。

这是程序的可观察行为。

¶7 构成交互式设备的内容是实现定义的。

¶8抽象和实际语义之间更严格的对应关系可以由每个实现来定义。

描述函数的库部分<stdio.h>说:

§7.21.3 文件

¶3 当流没有缓冲时,字符应尽快从源或目标出现。否则,字符可能会作为一个块累积并传输到主机环境或从主机环境传输。当一个流被完全缓冲时,当缓冲区被填满时,字符将作为一个块传输到主机环境或从主机环境传输。当流被行缓冲时,当遇到换行符时,字符旨在作为块传输到主机环境或从主机环境传输。此外,当缓冲区被填满时,当在非缓冲流上请求输入时,或者当在需要从主机环境传输字符的行缓冲流上请求输入时,字符将作为块传输到主机环境.

¶7 在程序启动时,预定义了三个文本流,不需要显式打开——标准输入(用于读取常规输入)、标准输出(用于写入常规输出)和标准错误(用于写入诊断输出)。最初打开时,标准错误流没有完全缓冲;当且仅当可以确定流不引用交互式设备时,标准输入和标准输出流才被完全缓冲。

请注意 §5.1.2.3 ¶6 中的“意图”注释。

§7.21.3 ¶7 中的规范意味着标准错误在程序启动时要么是无缓冲的,要么是行缓冲的,标准输入和标准输出要么是非缓冲的,要么是行缓冲的(通常是行缓冲的),除非输出不是交互式设备。在 Unix 上,磁盘文件、管道、FIFO、套接字(以及其他)不是交互式的。通常ttypty设备被认为是交互式的。

所以,如果你运行你的程序,输出到一个管道(例如 to catorlessmore),你可能*不会看到提示,但是如果你输入数字,你可能会得到提示,然后是第一行在一行上用换行符输出(并且您输入的数字不会出现)。如果从文件重定向输入,则根本看不到输入的值。如果您重定向到cat,您可能会在一行中看到您的输入,然后是提示和输出。如果您重定向到more,您可能根本看不到您的输入(与响应打印分开)。如果你重定向到less,你可能会得到各种有趣的屏幕效果,但仍然看不到你输入的内容。

您还需要修复修改后的代码。该%lf格式不适合读取整数(它是以前版本代码的遗留问题)。


*由于行为是实现定义的,实际发生的情况取决于您的实现。例如,一个实现可能会fflush(0)在任何输入之前执行等价的操作;这会将提示发送到设备。但是不需要任何实现来做到这一点,而且大多数都不是那么彻底(部分原因是这种彻底性具有与之相关的运行时成本)。

于 2013-10-05T19:10:17.910 回答
1

您可以运行一个实验:

printf("Enter a number: "); /* the prompt */
sleep(10); /* Add this. */
scanf("%lf", &number);

您会在 10 秒后看到弹出的提示。它没有记录 - 我知道 - 但在这种情况下它似乎scanf会导致stdout被刷新。

但是,您不应该指望这种行为,并且应该fflush(stdout)在打印提示字符串时。

于 2013-10-05T18:31:22.280 回答
1

这很可能是因为您的 C 标准库选择在其实现中刷新输出缓冲区scanf。这是个好主意,因为

  • 这是一个常见问题,您通常希望提示与光标位于同一行,并且
  • 这不是性能问题,因为等待用户输入比刷新缓冲区慢得多
于 2013-10-05T18:31:47.987 回答