【问题标题】:"\n" or '\n' or std::endl to std::cout? [duplicate]"\n" 或 '\n' 或 std::endl 到 std::cout? [复制]
【发布时间】:2012-01-08 19:26:44
【问题描述】:

自从我在写信给std::cout 时停止使用std::endl 结束行,并开始改用"\n" 以来,已经有很多年了。

但现在我开始看到更多使用'\n' 的sn-ps 代码,我开始想知道什么可能是最好的。

除了一个是字符串,另一个是字符之外,使用它还有什么好处:

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

关于这个:

std::cout << variable << "\n";

后期添加:

当我问这个问题时,我似乎认为换行符'\n' 刷新了缓冲区。现在我知道它取决于

默认情况下,std::cin 绑定到旧的 C stdin FILE* 流,std::cout 绑定到 stdout。换行符的刷新来自这种绑定。默认情况下,stdout,如果连接到终端,是行缓冲的。这意味着新行将刷新其缓冲区。因此,当使用std::cout 打印换行符时,将导致stdout 被刷新。

如果stdout 未连接到终端(例如,输出已被重定向或通过管道传输),或者如果std::coutstdout 之间的联系被破坏,则换行符不会刷新任何内容。

【问题讨论】:

  • 有趣的问题,我也想看看这个问题的答案。 :) 另外,你为什么停止使用std::endl
  • @Constantinius 我用using namespace stdstd::endl 停下来写太多了。 :)
  • @Joachim:您出于错误的原因停止使用它,但至少您停止使用它。 ;)
  • 您的编辑具有误导性。 std::endl记录以刷新缓冲流。 “大多数实现似乎都刷新了”是另一种说法“到目前为止我很幸运”——但公平地说,这只有在您关心刷新时间时才重要(恕我直言,这非常罕见)。

标签: c++ string character


【解决方案1】:

其实'\n'应该是默认的。除非您还想显式刷新流(以及何时以及为什么要这样做?),否则根本不需要使用 std::endl1
当然,很多书籍和教程都默认使用std::endl。这很不幸,可能会导致serious performance bugs

我想使用'\n'或使用"\n"之间没有什么区别,但后者是一个(两个)字符的数组,必须逐字符打印,必须设置循环,这比输出单个字符更复杂。当然,在执行 IO 时,这并不重要,但如果有疑问,当您想要输出一个字符文字时,请输出一个字符文字,而不是整个字符串文字。
这样做的一个很好的副作用是您在代码中传达了您打算只输出单个字符,而不是意外地这样做了。


1注意std::cout默认绑定到std::cin,这会导致std::cout在任何输入操作之前被刷新,这样任何提示都会被在用户必须输入内容之前打印。

【讨论】:

  • @JohnDibling: '\n' vs. "\n" 当然是一个微优化,但为什么会为时过早呢?你可以两者都写,那么为什么不写一个能表达你的意图并且可能更快又不会更慢的呢?这与++itit++ 的情况相同:它几乎不重要,但当它重要时,习惯于在重要的地方编写更快的代码是值得的。
  • @John:同样,"\n" 是过早的悲观。好的,所以它可能慢了一些微不足道的量,这很好,因为你想通过故意编写你认为很慢的代码来证明你对过早优化的风险是明智的。但是你不知道它比较慢,而且你必须写一些东西,所以你选择哪个?由于在可理解性上没有区别,我认为无论出于何种原因编写都是合理的,包括天真的猜测它可能更快一些,或者发出更小的代码
  • @JohnDibling:我没有像我应该的那样清楚地解释我的观点。我们不是在这里谈论优化。我们正在讨论从两种可能性中选择一种,一种更具表现力,不太可能更慢,并且可能更快。
  • @John:我认为问题在于要养成什么样的习惯,即“我通常应该做什么——考虑到这些选项对我来说看起来都差不多,有什么依据吗?根据经验法则?”。对性能的幼稚猜测与任何 IMO 一样都是决胜局。就避免std::endl 而言,我认为“不要告诉程序做你不想要的额外工作”是一个完全合理的经验法则,即使在没有分析的情况下也是如此。然后,"\n" 是否属于同一类别,字符串文字在某种意义上是否比字符文字“更多”,这有点令人费解。
  • @John: ++itit++ 在 99.99% 的情况下根本无关紧要。但是既然没关系,为什么不养成使用那 0.01% 中速度更快的习惯呢?在很多情况下,您需要选择一个默认值:制作单参数 ctor explicit,制作函数 const,前增量与后增量,'\n'std::endl,... 为什么不尝试总是做有优势的那个,不管这种情况多么罕见,优势多么微不足道?如果你可以选择其中一个,为什么不选择在 0.01% 中有优势的那个,如果它在剩余的 99.99% 中没有劣势?
【解决方案2】:

没有最好的。你用你需要的:

  • '\n' - 结束行
  • "some string\n" - 在某个字符串之后的行结束
  • std::endl - 结束行并刷新流

【讨论】:

  • “刷新流”的最简单解释是什么?提前非常感谢您!
【解决方案3】:

他们做不同的事情。 "\n" 输出一个换行符(以适当的特定于平台的表示形式,因此它在 Windows 上生成一个 "\r\n"),但 std::endl 执行相同的操作并刷新流。通常,您不需要立即刷新流,它只会降低性能,因此在大多数情况下没有理由使用std::endl

【讨论】:

    【解决方案4】:

    编辑:我的回答措辞不佳,这可能使人们相信我认为“\n”实际上打印了一个空字符。这当然是错误的:)

    编辑 2:查看 C++ 引用后,chars 无论如何都是通过引用传递的,所以那里没有区别。唯一的区别是必须在 cstring 中搜索分隔字符。 由于这个事实,以下内容不正确。

    '\n' 会比"\n" 稍微高效一些,因为后者最后还包含一个空字符,这意味着您将char* 发送到operator&lt;&lt;()(通常在一个32 位系统)而不是 char 的单个字节。

    在实践中,这是无关紧要的。就个人而言,我遵循弗拉基米尔概述的惯例。*

    【讨论】:

    • 因为它是一个 cstring。单个char ('\n') 将占用 1 个字节,而 cstrings 隐式附加了一个空字符,因此“\n”实际上是“\n\0”。这仍然是一个微不足道的问题。例如,sizeof("\n"); 在我的机器上返回 2。
    • 再次,不。字符串"\n"(以null结尾)具有静态存储持续时间,根本不支持在运行时构造。
    • @jalf 但是在找到 '\0' 之前,在字符数组上进行迭代仍然是有代价的。
    • @ChristianRau:是的,但在 "\n" 与 '\n' 的情况下,成本将非常低。
    • @ChrisParton 当然,我们在这里都在谈论最小化,但您的回答并非完全错误,'\n'"\n" 之间确实存在性能差异。
    【解决方案5】:
    • std::cout &lt;&lt; variable &lt;&lt; std::endl;

      std::endl 输出一个换行符,但它也会刷新输出流。也就是说,和

      一样的效果
      std::cout << variable << '\n'; // output newline
      std::cout.flush();      // then flush 
      
    • std::cout &lt;&lt; variable &lt;&lt; '\n';

      '\n'char, 输出一个换行符,因此将使用ostream&amp; operator&lt;&lt; (ostream&amp; os, char c);

    • std::cout &lt;&lt; variable &lt;&lt; "\n";

      "\n"const char[2],因此将使用 ostream&amp; operator&lt;&lt; (ostream&amp; os, const char* s);。我们可以想象,这个函数将包含一个循环,我们可能会争辩说只打印一个换行符是多余的。

    【讨论】:

      【解决方案6】:

      std::endl 刷新流。当您想要发生这种情况时-例如因为您希望用户及时看到您的输出——您应该使用std::endl 而不是将'\n' 写入流(无论是作为孤立字符还是字符串的一部分)。

      有时,您无需自己显式刷新流即可逃脱;例如在 linux 环境中,如果 coutSTDOUT 同步(这是默认设置)并且正在写入终端,则默认情况下,流将被行缓冲,并且会自动刷新每个是时候写一个新行了。

      但是,依赖这种行为是有风险的。例如在相同的 linux 环境中,如果您决定在运行程序时将stdout 重定向到文件或通过管道传输到另一个进程,那么默认情况下,流将被块缓冲

      同样,如果您稍后决定关闭与 stdio 的同步(例如为了提高效率),那么实现将倾向于使用 iostream 的缓冲机制,它没有行缓冲模式。

      我看到由于这个错误而浪费了很多生产力;如果输出在写入时应该是可见的,那么您应该明确使用std::endl(或使用std::flushstd::ostream::flush,但我通常觉得std::endl 更方便),或者做其他事情来确保经常发生刷新足够了,例如将stdout 配置为行缓冲(假设足够了)。

      【讨论】:

        猜你喜欢
        • 2015-04-19
        • 1970-01-01
        • 2017-05-13
        • 2020-03-19
        • 2020-12-12
        • 2020-07-23
        • 2012-03-27
        相关资源
        最近更新 更多