所以我写了一个测试程序,这里是代码
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int i;
printf("%s", "entering\n");
fflush(stdout);
for (i = 0 ; i < 3 ; i++)
{
fork();
fflush(stdout);
}
printf("%s", "exiting\n");
}
Run Code Online (Sandbox Code Playgroud)
当我在终端中编译并运行它时,它会显示我所期望的:"进入"一次,"退出"一些.当我运行它并将输出重定向到文件时,它会显示每个退出的输入.
1)为什么每次都不向终端和文件输出相同的东西?
2)为什么它显示8次输入文件但没有在终端输入一次(一次是我期望它做的).
3)当我的输出转到文件时,fflush()语句会有所不同吗?
它与标准文件句柄上的缓冲有关.从ISO C99 7.19.3/7 Files:
最初打开时,标准错误流未完全缓冲; 当且仅当可以确定流不参考交互设备时,标准输入和标准输出流被完全缓冲.
当您写入终端时,输出很可能是(a)行缓冲,这意味着只要发送换行符就会刷新它.
通过重定向,它是完全缓冲的,这意味着它只会在缓冲区满时才会刷新.
您可以setvbuf在操作之前使用stdout,将其设置为无缓冲或行缓冲,您不必担心刷新.
setvbuf (stdout, NULL, _IONBF, BUFSIZ); // _IONBF for no buffering.
// _IOFBF for full buffering.
// _IOLBF for line buffering.
Run Code Online (Sandbox Code Playgroud)
请记住,如果您将输出发送到文件,无缓冲输出可能会影响性能.另请注意,对此的支持是实现定义的,不受标准保证.
C99第7.19.3/3节是相关位:
当流未缓冲时,字符应尽快从源或目的地出现.否则,可以将字符作为块累积并发送到主机环境或从主机环境发送.
当流被完全缓冲时,当填充缓冲区时,字符将作为块传输到主机环境或从主机环境传输.
当流被行缓冲时,当遇到换行符时,字符将作为块传输到主机环境或从主机环境传输.
此外,当填充缓冲区,在无缓冲流上请求输入时,或者在需要从主机环境传输字符的行缓冲流上请求输入时,字符旨在作为块传输到主机环境. .
对这些特性的支持是实现定义的,并且可能通过
setbuf和setvbuf函数受到影响.
(a)标准未指定标准输入和输出是无缓冲的还是行缓冲的,其中基础文件可能是交互式的(参见此处).线路缓冲是我遇到的最常见的(到目前为止).
至于为什么你得到多条entering消息,即使你在分叉之前刷新它,这是一个更棘手的问题.你没有列出你的环境,所以这是最好的假设,但我看到了一些可能性(虽然可能会有更多).
首先,fflush由于某种原因,可能会失败.这实际上是可行的,但很容易检查,因为它的行为类似于write(因为它通常在封面下调用 write).
换句话说,errno在冲洗后检查是否存在问题.如果是这样,C运行时缓冲区仍将在所有子节点中刷新,因此它们都将写入entering.
其次,即使刷新了缓冲区,也可能在下面(在该write级别或在终端驱动程序本身内)进行更多缓冲,这些缓冲由其复制fork,从而导致到终端的多个输出.我认为这不太可能.
第三,这可能只是一个奇怪的平台特定问题.当我在Ubuntu 11.04盒子上运行你的代码时,我发现终端输出和文件输出变体之间没有区别.它们都输出一条entering和八条exiting消息.
如果第三个是这种情况那么你真的没有追索权:ISO C并没有强制要求在这种情况下发生的事情,因为ISO C一无所知fork.我在POSIX.1中找不到任何似乎表明这种或那种方式的东西,但它可能存在.
对于它的价值,如果我只注释掉第一个fflush,我会得到entering两次,然后是八条exiting消息.如果我只评论第二个,它就像它们在那里一样,一个entering接着是八个exiting.
如果我评论他们两个,我得到八entering/exiting对.