C++:如何刷新stdout缓冲区?

26

我有一些使用cout语句进行调试的C++代码,但不知何故,除非我在结尾处执行std::cout.flush();,否则无法打印所有数据。

我不太理解为什么需要执行刷新操作。

有人有任何见解吗?

7个回答

22

补充前面的答案:你的调试语句应该写到cerr中,因为:

  • 它会将信息写入标准错误流,这意味着在运行应用程序时,你可以通过重定向轻松地将“正常”程序输出与错误/调试信息分开;
  • 最重要的是,默认情况下,cerr不带缓冲的,这意味着在每次输出操作之后,它会自动刷新自己,通常这对于错误和调试输出是有益的。

(来源:C++标准,§27.3.1 ¶4-5,§27.4.2.1.2 表 83)


谢谢,我会记住这个以备将来参考。通常我不在意,因为我会删除我的cout语句,但是这个项目真的让我头疼。我讨厌第三方代码。 - Dixon Steel

13

你是否在使用std::endl来结束每一行?这应该是常规做法,除非出于性能问题需要使用其他方式,但由于某些原因,我看到有很多代码使用'\n'代替。

另外,你也可以这样做:

std::cout.setf( std::ios_base::unitbuf );

main 函数的最开始加入这一行。这样会导致在每个 << 结尾处都进行刷新,这比你实际需要的更频繁,但对于向控制台输出诊断信息来说,可能是可以接受的。


是的,我有这个习惯,但我正在集成的一些代码并没有这样做,而且对于我来说它相当庞大,很难“纠正”它。 - Dixon Steel
@Dixon Steel 我知道你的感受。这就是为什么我提出了第二个建议,使用 unitbuf - James Kanze
为什么应该将std::endl作为常规做法? - 9769953
因为它简化了调试过程。(显然,如果程序只是输出大量文本,你会希望通过使用\n进行优化。但这应该被视为一种优化,而不是在性能不重要时的默认行为。) - undefined

4

自动刷新不完全的数据是否缺少结尾的\n?默认情况下,标准输出在看到回车符之前不会被传递。


如果我发送一个 endl,它也会打印,但是我认为在 C++ 中这与刷新操作相同吗? - Dixon Steel
换行符被用作“刷新点”,如果你愿意的话。请记住,C使用与C++相同的底层I/O,而C缺少endl,但是\n仍然很好用。std::endl实际上可能会强制刷新;我需要检查它的实现(或听取已经了解的人的意见)才能确定。 - mah
1
这是错误的。标准输出并没有进行行缓冲。在涉及到缓冲时,iostream 的工作方式与 FILE 相比有很大不同。通过显式调用 flush (包括由 std::endlstd::cin 的读取触发的调用),或者在其他由实现决定的未指定时间,std::cout 将被刷新。在 iostream 中没有行缓冲。 - James Kanze
std::endl 是一个刷新操作,而不仅仅是换行符。'\n' 不会刷新,std::endl 会刷新 iostream。 - berkus
天哪!开发MinGW版本的gdb的人不知道,没有人设置回车符。太可怕了!我的代码在GNU/Linux上完美运行,但自从我在Windows®上运行它以来,打印输出只在gdb中混乱,而在普通终端中则没有问题。这只有当我添加了\r标记后才得到修复。我真的无话可说。顺便说一下,据我所知,stdout应该在“换行符”而不是“回车符”上刷新。 - Hi-Angel

1

这是否意味着输出可能是不可预测的,而且我在流上并没有真正的错误或死锁? - Dixon Steel

1

1
在C++中,你可以使用`endl`格式化符号与`cout`操作符一起使用,而不是使用`flush`。

0

std::endl 的答案只在需要回车时才有效。 如果想要将命令提示符刷新,不确定该如何实现。


这篇帖子(https://softwareengineering.stackexchange.com/questions/386269/why-do-you-want-to-avoid-flushing-stdout)似乎有解决方案。 - MoralCode

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接