C 为什么printf在调用后不刷新,除非换行符是格式字符串?

C 为什么printf在调用后不刷新,除非换行符是格式字符串?,c,printf,flush,C,Printf,Flush,为什么printf在调用后不刷新,除非换行符的格式为字符串?这是POSIX行为吗?我怎么可能每次都立即刷新printf 要获得即时输出,请执行以下任一操作: 打印到stderr 使标准件无缓冲 要立即刷新调用fflush(stdout)或fflush(NULL)(NULL表示刷新所有内容)。您可以将fprintf改为无缓冲的stderr。或者你可以在需要的时候冲洗标准液。或者,您可以将stdout设置为unbuffered。默认情况下,stdout流是行缓冲的,因此仅在到达换行符后(或被告知时)

为什么
printf
在调用后不刷新,除非换行符的格式为字符串?这是POSIX行为吗?我怎么可能每次都立即刷新
printf

要获得即时输出,请执行以下任一操作:

  • 打印到stderr
  • 使标准件无缓冲

  • 要立即刷新调用
    fflush(stdout)
    fflush(NULL)
    NULL
    表示刷新所有内容)。

    您可以将fprintf改为无缓冲的stderr。或者你可以在需要的时候冲洗标准液。或者,您可以将stdout设置为unbuffered。

    默认情况下,
    stdout
    流是行缓冲的,因此仅在到达换行符后(或被告知时)显示缓冲区中的内容。您有几个选项可以立即打印:

    使用
    fprintf
    打印到
    stderr
    stderr
    is):

    使用
    fflush
    随时刷新标准输出:

    printf("Buffered, will be flushed");
    fflush(stdout); // Will now print everything in the stdout buffer
    
    编辑:根据Andy Ross下面的评论,您还可以使用
    setbuf
    禁用标准输出上的缓冲:

    setbuf(stdout, NULL);
    
    或其安全版本
    setvbuf
    ,如前所述


    这可能是因为效率的原因,也可能是因为如果有多个程序写入一个TTY,这样就不会让一行上的字符交错。因此,如果程序A和B正在输出,通常会得到:

    program A output
    program B output
    program B output
    program A output
    program B output
    
    这很臭,但总比

    proprogrgraam m AB  ououtputputt
    prproogrgram amB A  ououtputtput
    program B output
    

    请注意,它甚至不能保证在换行符上刷新,因此如果刷新对您很重要,您应该显式刷新。

    默认情况下,stdout是行缓冲的,stderr是无缓冲的,文件是完全缓冲的。

    注意:Microsoft运行时库不支持行缓冲,因此
    printf(“将立即打印到终端”)


    不,这不是POSIX行为,而是ISO行为(好吧,这是POSIX行为,但仅在它们符合ISO的情况下)

    如果可以检测到标准输出引用的是交互设备,则它是行缓冲的,否则它是完全缓冲的。因此,在某些情况下,
    printf
    即使有换行符要发送,也不会刷新,例如:

    myprog >myfile.txt
    
    这对于提高效率很有意义,因为如果您与用户交互,他们可能希望看到每一行。如果将输出发送到文件,则最有可能的情况是另一端没有用户(尽管并非不可能,但他们可能正在跟踪文件)。现在你可以说用户想要看到每个角色,但这有两个问题

    首先,它的效率不是很高。第二,最初的ANSI C指令主要是对现有行为进行编码,而不是发明新的行为,而这些设计决策早在ANSI开始这一过程之前就已经做出了。即使是现在的ISO在修改标准中的现有规则时也非常谨慎

    至于如何处理这个问题,如果您在希望立即看到的每个输出调用之后
    fflush(stdout)
    ,这将解决问题

    或者,您可以在操作
    stdout
    之前使用
    setvbuf
    ,将其设置为无缓冲,这样您就不必担心将所有
    fflush
    行添加到代码中:

    setvbuf (stdout, NULL, _IONBF, BUFSIZ);
    
    请记住,如果将输出发送到文件,可能会对性能产生相当大的影响。还要记住,对这一点的支持是由实现定义的,而不是由标准保证的

    ISO C99第7.19.3/3节为相关位:

    当流未缓冲时,字符将尽快从源或目标显示。否则,字符可以作为块累积并传输到主机环境或从主机环境传输

    当一个流被完全缓冲时,当缓冲区被填满时,字符将作为一个块传输到主机环境或从主机环境传输

    当流被行缓冲时,当遇到新行字符时,字符将作为块传输到主机环境或从主机环境传输

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

    对这些特性的支持由实现定义,并可能通过
    setbuf
    setvbuf
    功能受到影响


    使用
    setbuf(stdout,NULL)禁用缓冲。

    通常有两个缓冲级别-

    1。内核缓冲区缓存(提高读/写速度)

    2。I/O库中的缓冲(减少系统调用次数)

    让我们以
    fprintf和write()为例

    调用
    fprintf()
    时,它不会直接写入文件。它首先进入程序内存中的stdio缓冲区。通过使用write系统调用将其写入内核缓冲区缓存。因此,跳过I/O缓冲区的一种方法是直接使用write()。其他方法是使用
    setbuff(stream,NULL)
    。这将缓冲模式设置为无缓冲,数据直接写入内核缓冲区。 为了强制将数据转移到内核缓冲区,我们可以使用“\n”,在默认缓冲模式为“行缓冲”的情况下,它将刷新I/O缓冲区。 或者我们可以使用
    fflush(文件*流)

    现在我们在内核缓冲区中。内核(/OS)希望最小化磁盘访问时间,因此它只读取/写入磁盘块。因此,当发出一个
    read()
    时,这是一个系统调用,可以直接调用,也可以通过
    fscanf()
    调用,内核从磁盘读取磁盘块并将其存储在缓冲区中。之后,数据将从此处复制到用户空间

    西米尔
    myprog >myfile.txt
    
    setvbuf (stdout, NULL, _IONBF, BUFSIZ);