Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在执行scanf之前,printf是如何刷新的?_C_Linux_Printf_Scanf_Buffering - Fatal编程技术网

在执行scanf之前,printf是如何刷新的?

在执行scanf之前,printf是如何刷新的?,c,linux,printf,scanf,buffering,C,Linux,Printf,Scanf,Buffering,我最近读了很多关于标准输出缓冲的书。我知道printf是缓冲的,但到目前为止,我认为只有在将新行读入缓冲区或调用fflush(stdout)或调用printf的进程正常退出时,它的缓冲区才会被刷新 我编写了这个程序,在scanf之前调用printf,但没有新行。当我在谷歌上搜索时,我发现很多人说他们不明白为什么scanf在printf之前被处决。因为我现在理解了标准输出缓冲的概念,这对我来说是有意义的 然而,在我的例子中,缓冲区是在我运行scanf之前刷新的。这样做是有意义的,因为用户可能希望在

我最近读了很多关于标准输出缓冲的书。我知道
printf
是缓冲的,但到目前为止,我认为只有在将新行读入缓冲区或调用
fflush(stdout)
或调用
printf
的进程正常退出时,它的缓冲区才会被刷新

我编写了这个程序,在
scanf
之前调用printf,但没有新行。当我在谷歌上搜索时,我发现很多人说他们不明白为什么scanf在printf之前被处决。因为我现在理解了标准输出缓冲的概念,这对我来说是有意义的

然而,在我的例子中,缓冲区是在我运行scanf之前刷新的。这样做是有意义的,因为用户可能希望在任何scanf之前执行printf,但是它是如何发生的呢?法拉盛标准酒到底是什么?是斯坎夫吗

int main(无效){
烧焦东西;
printf(“你好”);
scanf(“%c”和事物);
}
(我正在运行Arch Linux)


编辑:由于一些评论说我的系统的标准输出是无缓冲的,我只想补充一点,在我的程序上不运行
scanf
,我的程序完全有我上面提到的行为,它肯定是缓冲的。

这是一个实现质量问题

C标准仅要求默认情况下,只有在附加到常规文件时,
stdin
stdout
才被完全缓冲。但它明确鼓励交互设备的特定行为:

5.1.2.3程序执行
[…]
一致性实施的最低要求为:
[…]
交互设备的输入和输出动态应按照7.21.3的规定进行。这些要求的目的是尽快出现无缓冲或行缓冲输出,以确保提示消息在程序等待输入之前出现

在许多Posix系统上,当连接到字符设备时,
stdin
stdout
是行缓冲的,当从
stdin
读取的尝试需要从底层系统句柄读取时,
stdout
会自动刷新。这样,即使没有尾随换行符,也可以在终端上显示提示

在linux上,此行为在中指定:

涉及终端设备的输出流始终是线性的 默认缓冲;写入这些流的挂起输出 每当输入流引用终端时自动执行 设备被读取。在需要大量计算的情况下 在输出终端上打印一行的一部分后完成,即 在启动和关闭前,必须刷新(3)标准输出 计算以使输出显示

然而GNU libc有一个微妙的不同行为:只有
stdout
按照中的编码以这种方式刷新(由Ulrich Drepper于2001-08-04 23:59:30修改):

/*读取前刷新所有行缓冲文件*/
/*FIXME这个可以/应该移动到genops*/
如果(fp->_标志和(_IO_线_BUF | u IO_无缓冲))
{
#如果0
直觉(_IO_flush_all_linebuffered)();
#否则
/*我们以前会刷新所有行缓冲流。这真的不是
任何标准都需要。我记得
传统的Unix系统对stdout.stderr做得更好
没有行缓冲,所以我们在这里就这样做
明确地说。--德雷珀*/
_IO_获取_锁(_IO_stdout);
如果((_IO_stdout->_标志和(_IO_链接| u IO_NO_写入| u IO_行_BUF))
==(|IO_链接| u IO_线_BUF))
_IO_溢出(_IO_stdout,EOF);
_IO_释放_锁(_IO_stdout);
#恩迪夫
}
我认为只有在将新行读入缓冲区或调用
fflush(stdout)
或调用
printf
的进程正常退出时,才会刷新其缓冲区

这不是C标准的意图。当一个流是行缓冲流时,当程序请求输入任何未缓冲流或从“主机环境”(如用户输入的终端窗口)获取输入的行缓冲流时,也应刷新输出,如C 2018 7.21.3 3所述:

…当对流进行行缓冲时,当遇到新行字符时,字符将作为块传输到主机环境或从主机环境传输。此外,当缓冲区被填满时,当在无缓冲流上请求输入时,或者当在需要从主机环境传输字符的行缓冲流上请求输入时,字符打算作为块传输到主机环境

这只是表达了一种意图,标准进一步指出,对这些特性的支持是由实现定义的,因此这在技术上是一个实现质量问题。但是,从诊断信息的质量来看,这不是一个质量问题。如下文所述,对实现定义的支持以及标准输出是否是行缓冲的保留,在很大程度上是对各种旧计算机系统的可行性或可能性的让步。在大多数现代C实现中,C实现不应使用C标准规定的许可证作为不实现这些功能的借口

下面是一个从无关流读取输入如何刷新标准输出的示例。当我使用Xcode 11.3.1在macOS 10.14.6上执行此程序时,当读取与
/dev/null
无关的流时,标准输出中的“Hello”将被刷新,但当仅使用
printf写入输出时,则不会刷新:

#include <stdio.h>
#include <unistd.h>


int main(void)
{
    printf("Hello");
    FILE *dummy = fopen("/dev/null", "r");
    setvbuf(dummy, NULL, _IONBF, 0); // Make dummy unbuffered.
    fgetc(dummy);       // "Hello" appears on terminal.
    printf(" world.");  // " world." does not appear on terminal.
    sleep(5);
    printf("\n");       // " world." appears on terminal.
}
#包括
#包括
内部主(空)
{
printf(“你好”);
FILE*dummy=fopen(“/dev/null”,“r”);
setvbuf(dummy,NULL,_IONBF,0);//使dummy无缓冲。
fgetc(虚拟);//“Hello”出现在术语中