C ++:“ std :: endl”和“ \ n”


568

许多C ++书籍都包含这样的示例代码...

std::cout << "Test line" << std::endl;

...所以我也总是这样做。但是,我已经从工作的开发人员那里看到了很多这样的代码:

std::cout << "Test line\n";

是否有技术上的理由要优先于另一个,还是仅仅是编码风格的问题?




25
@derobert,这个人比另一个人年长
Kira

3
@HediNaily确实是。但是另一方的回答使我感到好些,因此我选择了这种方式。另外,另一个稍微宽一点,也涵盖了'\n'
derobert 2013年

stackoverflow.com/a/30968225/3163618可能会有明显的性能差异。
qwr

Answers:


473

假设文件以文本模式打开,那么行尾字符的变化并不重要,除非您要求输入二进制文件,否则这就是您得到的。编译后的程序将为系统编译出正确的东西。

唯一的区别是std::endl刷新输出缓冲区,'\n'但不刷新。如果您不希望频繁刷新缓冲区,请使用'\n'。如果这样做(例如,如果要获取所有输出,并且程序不稳定),请使用std::endl


24
或者考虑使用::std::cerr代替,::std::cout因为每个输出操作都对它进行无缓冲和刷新。
2010年

142
@Omnifarious:不应为错误保留std :: cerr。这两个流不会同步在一起,因此如果您将某些文本输出到cout,它可能会被缓冲,并且cerr将直接输出到输出,从而导致混合模式显示。使用cerr表示预期的(错误),使用cout表示预期的功能(正常交互)。
马丁·约克

23
@Lucas:平台意识不超过'\ n'。
CB Bailey 2010年

32
@LokiAstari:我不会说这stderr是“错误”。相反,如果需要,它用于带外诊断消息。应该可以说./prog > file和存储真正的程序有效负载,但是即使在正常交互中,程序也可能希望输出更多的状态信息。
Kerrek SB 2011

13
“在许多实现中,标准输出是行缓冲的,并且除非执行了std :: cout.sync_with_stdio(false),否则写'\ n'都会导致刷新。” 从这里复制
GuLearn 2013年

249

差异可以通过以下方式说明:

std::cout << std::endl;

相当于

std::cout << '\n' << std::flush;

所以,

  • 采用 std::endl如果要强制立即刷新到输出。
  • \n如果您担心性能,请使用(如果使用<<运算符,则可能不是这种情况)。

\n在大多数行上使用。
然后使用std::endl在段落的末尾(但这只是一种习惯,通常不是必需的)。

与其他主张相反,\n仅当流将要到达文件(std::cin并且std::cout是特殊但仍是文件(或类似文件))时,才将字符映射到正确的平台行尾。


5
在许多情况下,“立即查看输出”是一条红色鲱鱼,因为cout它与绑定在一起cin,这意味着,如果您从读取输入cincout则将首先刷新。但是,如果您想显示进度条或其他内容而不从中读取cin,那么可以肯定,刷新很有用。
克里斯·杰斯特·杨

9
@LokiAstari:如果使用<<操作符,则可能不担心性能 -为什么?我不知道那operator<<不是性能表现,或者还有什么替代性能的表现?请为我指出一些材料,以进一步理解这一点。
legends2k 2014年

8
@ legends2k:有一个古老的妻子故事,即C ++流的性能不如C printf()。尽管在一定程度上是正确的,但是速度的主要差异是由人们错误地使用C ++流引起的。stackoverflow.com/a/1042121/14065在C ++中,请记住要使iostream与C流sync_with_stdio(false)不同步,并且不要连续刷新输出。让图书馆弄清楚什么时候去做。stackoverflow.com/a/1926432/14065
马丁·约克

6
@Loki:有一个城市传说sync_with_stdio使iostream像stdio一样快。 它不是
Ben Voigt

2
@BenVoigt:我对上面的措辞很谨慎(所以我对他们很满意)。它的性能不如stdio(因为它做得更多)。但是人们抱怨的许多性能差距是由与stdio同步引起的。
马丁·约克


30

如果要使用该函数,则意味着存在另一个函数调用 std::endl

a) std::cout << "Hello\n";
b) std::cout << "Hello" << std::endl;

a)<<一次致电接线员。
b)<<两次呼叫接线员。


19
这可能很明显,但是它对线程程序产生了巨大的影响,通常,第一个版本将在一个快照中写入一行,而第二个版本可能会被其他线程的写入操作分开。我经常发现自己写了std :: cout <<“ hello \ n” << std :: flush来避免这种情况。
smparkes 2011年

std::cout << "Hello" << "\n";
byxor

1
@byxor除了其他答案中描述的缓冲区刷新外,几乎相同。无论如何,当您可以将两个字符串文字合并为一个时,这是多余的。
iBug

好吧,如果要打印的字符串不是文字,那么在a<<的情况下,对a的调用也将为2 ,因此我不会声称需要一个或两个<<(或两个函数调用)\n和之间的区别endl
恩里科·玛丽亚·德·安吉利斯

大声笑,这不是我使用\ n的原因。
卡罗·伍德

28

我记得在标准中对此有所了解,所以这里是:

请参阅C11标准,该标准定义了标准流的行为,因为C ++程序与CRT接口,因此C11标准应在此处管理刷新策略。

ISO / IEC 9899:201x

7.21.3§7

在程序启动时,预定义了三个文本流,无需显式打开它们-标准输入(用于读取常规输入),标准输出(用于写入常规输出)和标准错误(用于写入诊断输出)。最初打开时,标准错误流未完全缓冲;当且仅当可以确定该流不引用交互式设备时,标准输入流和标准输出流才被完全缓冲。

7.21.3§3

当流没有缓冲时,字符应尽快从源或目的地出现。否则,字符可能会作为块被累积并传输到主机环境或从主机环境传输。当流被完全缓冲时,打算在填充缓冲区时将字符作为块与主机环境进行传输。当流被行缓冲时,字符将在遇到换行符时作为块与主机环境进行传输。此外,当填充缓冲区,在无缓冲流上请求输入或在需要从主机环境传输字符的行缓冲流上请求输入时,打算将字符作为块传输到主机环境。 。

这意味着,std::coutstd::cin是完全缓冲当且仅当他们所指的非交互设备。换句话说,如果将stdout连接到终端,则行为上没有差异。

但是,如果std::cout.sync_with_stdio(false)被调用,那么'\n'即使是交互式设备也不会引起刷新。否则'\n'等效于std::endl除非管道到文件:std :: endl上的c ++ ref


19

他们都将编写适当的行尾字符。除了那个endl,还会导致缓冲区被提交。您通常在执行文件I / O时不希望使用endl,因为不必要的提交会影响性能。



10

如果您使用Qt和endl,则可能会意外地使用不正确的endl结果,从而给您带来非常令人惊讶的结果。请参见以下代码段:

#include <iostream>
#include <QtCore/QtCore> 
#include <QtGui/QtGui>

// notice that there is no "using namespace std;"
int main(int argc, char** argv)
{
    QApplication qapp(argc,argv);
    QMainWindow mw;
    mw.show();
    std::cout << "Finished Execution!" << endl;
    // This prints something similar to: "Finished Execution!67006AB4"
    return qapp.exec();
}

请注意,我写的endl不是std::endl(本来是正确的),显然是endlqtextstream.h(它是QtCore的一部分)中定义了一个函数。

使用"\n"而不是endl完全回避任何潜在的名称空间问题。这也是一个很好的例子,为什么将符号放入全局名称空间(默认情况下像Qt一样)不是一个好主意。


31
啊!谁愿意成为using namespace std;?:-)
史蒂夫·弗利

2
讨厌。感谢您的评论,我敢肯定其他人也会遇到这种情况。
极客头球2010年

@SteveFolly,我愿意。为什么不?
2015年

@ʇolɐǝzǝɥʇqoq可以,只要您不在头文件中这样做就可以。
smerlin

1
@ʇolɐǝzǝɥʇqoq请避免using namespace std;。这被认为是不良做法。请参阅为什么“使用名称空间标准”;被认为是不良做法?
LF


2

std::endl操纵器等效于 '\n'。但是std::endl总是冲洗流。

std::cout << "Test line" << std::endl; // with flush
std::cout << "Test line\n"; // no flush

1

如果您打算在自己的笔记本电脑以外的其他任何设备上运行程序,则永远不要使用该endl语句。尤其是如果您要写很多短行或者我经常在文件中看到单个字符。使用的endl就是知道杀像NFS网络文件系统。


那是因为潮红吗?我可以看到这是有可能的。
极客头

@头确实。我还看到它破坏了磁盘IO性能。
sbi

0

参考这是一个只输出I / O操作器

std::endl在输出序列os中插入换行符,并通过调用os.put(os.widen('\n'))后跟来刷新它os.flush()

何时使用:

该操纵器可用于立即产生一行输出

例如

显示长时间运行的进程的输出时,可能会意外崩溃的多个线程的日志记录活动或程序的日志记录活动。

如果生成的进程执行任何屏幕I / O,则在调用std :: system之前也必须显式刷新std :: cout。在大多数其他常见的交互式I / O场景中,std :: endl与std :: cout一起使用时是多余的,因为任何来自std :: cin的输入,输出到std :: cerr或程序终止都会强制调用std :: cout .flush()。在某些来源的鼓励下,使用std :: endl代替'\ n'可能会大大降低输出性能。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.