#include <stdio.h>
int main()
{
int age;
printf("Enter Your age: ");
scanf("%lf", &age);
printf("Your age is %d\n", age);
return 0;
}
如果我们运行程序,提示将显示在终端屏幕上,即使提示末尾没有换行符。这怎么可能发生?
#include <stdio.h>
int main()
{
int age;
printf("Enter Your age: ");
scanf("%lf", &age);
printf("Your age is %d\n", age);
return 0;
}
如果我们运行程序,提示将显示在终端屏幕上,即使提示末尾没有换行符。这怎么可能发生?
如评论中所述,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、套接字(以及其他)不是交互式的。通常tty
,pty
设备被认为是交互式的。
所以,如果你运行你的程序,输出到一个管道(例如 to cat
orless
或more
),你可能*不会看到提示,但是如果你输入数字,你可能会得到提示,然后是第一行在一行上用换行符输出(并且您输入的数字不会出现)。如果从文件重定向输入,则根本看不到输入的值。如果您重定向到cat
,您可能会在一行中看到您的输入,然后是提示和输出。如果您重定向到more
,您可能根本看不到您的输入(与响应打印分开)。如果你重定向到less
,你可能会得到各种有趣的屏幕效果,但仍然看不到你输入的内容。
您还需要修复修改后的代码。该%lf
格式不适合读取整数(它是以前版本代码的遗留问题)。
*由于行为是实现定义的,实际发生的情况取决于您的实现。例如,一个实现可能会fflush(0)
在任何输入之前执行等价的操作;这会将提示发送到设备。但是不需要任何实现来做到这一点,而且大多数都不是那么彻底(部分原因是这种彻底性具有与之相关的运行时成本)。
您可以运行一个实验:
printf("Enter a number: "); /* the prompt */
sleep(10); /* Add this. */
scanf("%lf", &number);
您会在 10 秒后看到弹出的提示。它没有记录 - 我知道 - 但在这种情况下它似乎scanf
会导致stdout
被刷新。
但是,您不应该指望这种行为,并且应该fflush(stdout)
在打印提示字符串时。
这很可能是因为您的 C 标准库选择在其实现中刷新输出缓冲区scanf
。这是个好主意,因为