为什么在此代码中,如果没有打印任何换行符,则刷新缓冲区?

时间:2015-10-13 06:18:58

标签: c windows gcc

#include <stdio.h>
#include <limits.h>
#include <windows.h>

void p(int n) {

    if (n == 0) return;

    p(n/10);

    if (n%10 < 5) {printf("%d",n%10); Sleep(1000);}

}

int main()
{
    printf("%d\n",INT_MAX-1);

    p(INT_MAX - 1);

    return 0;
}

它应该一次打印所有内容,因为流是缓冲的,但它会分别打印数字。我在windows下使用gcc。

3 个答案:

答案 0 :(得分:4)

在C中,流有三种可能的缓冲状态:

  • _IONBF - 无缓冲;字符应该尽快出现
  • _IOLBF - 行缓冲;字符应出现在换行符后
  • _IOFBF - 完全缓冲;在流刷新之前不应出现字符

关于stdout的初始状态,C11 7.21.3 / 7必须说:

  

最初打开时,标准错误流未完全缓冲;当且仅当可以确定流不参考交互设备时,标准输入和标准输出流是完全缓冲的。

由于流 是您的案例中的交互式设备,因此不得完全缓冲。因此,stdout可以是行缓冲的也可以是非缓冲的。我没有看到任何其他文字进一步缩小这一点。

显然在您的系统上,它以无缓冲模式启动。

您可以使用以下方式设置线路缓冲:

setvbuf(stdout, NULL, _IOLBF, 1024);

(我不确定你应该为最后一个参数放置什么,但我认为这意味着它应该为该行使用1024字节的缓冲区;如果达到该限制则刷新)

然而,当我在MinGW-w64 4.9.2上尝试此操作时,行缓冲似乎与完全缓冲的行为相同。

我推测原因是因为此实现尽可能地将功能重定向到MSVC运行时库,并且MSVC运行时可能不支持行缓冲。这可以解释为什么gcc决定默认为无缓冲,因为这对于交互式程序而言比完全缓冲更好。

答案 1 :(得分:0)

在linux下的gcc上,这段代码:

#include <stdio.h>
#include <limits.h>

void p(int n){
    if (n == 0) return;

    p(n/10);

    printf("%d",n);
}

int main()
{
    printf("%d\n",INT_MAX-1);

    p(INT_MAX - 1);

    printf("\n");
    return 0;
}

给出这个输出:

2147483646                                                                                                                                                                                                                                      
2212142147214742147482147483214748362147483642147483646 

或者为了清晰起见:

 2 21 214 2147 21474 214748 2147483 21474836 214748364 2147483646

为了清晰起见,我已经取消了你的n%10的东西(因为我真的不明白为什么会这样)。

显然,我的系统没有刷新,我猜它必须是Windows本身正在做的事情。你的代码很好。

答案 2 :(得分:0)

在Linux上使用以下测试程序:     #include

int main(int ac, char **av)
{
    fprintf(stderr, "Pre\n");
    printf("Hello world");
    fprintf(stderr, "Post\n");
    return 0;
}

运行时产生以下输出:

Pre<newline>
Post<newline>
Hello world<no newline>

鉴于[line buffered] stdout在[unbuffered] stderr之后出现,暗示缓冲区是用atexit处理程序刷新的,或者当程序终止并且libc被解除引用时。运行strace和ltrace表示第一个情况没有发生,因此输出可能在退出时刷新。

我怀疑在这个级别上,Windows和Linux的行为是一致的。如果它指向的是一个非stdout的文件,那么如果你忘了关闭文件,stdio子系统允许损坏文件(丢失的数据)将是非常糟糕的形式。