"std::endl"与" line break "

"std::endl" vs " "

本文关键字:break line endl std      更新时间:2023-10-16

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

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

。所以我也一直这样做。但是我已经看到很多来自工作开发人员的代码,如下所示:

std::cout << "Test linen";

是否有技术原因偏爱一个而不是另一个,或者这只是编码风格的问题?

不同的行尾字符无关紧要,假设文件以文本模式打开,除非您要求二进制,否则您将获得此。 编译的程序将为编译的系统写出正确的内容。

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

差异可以通过以下几点来说明:

std::cout << std::endl;

相当于

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

所以

  • 如果要强制立即刷新输出,请使用std::endl
  • 如果您担心性能,请使用n(如果您使用的是<<运算符,则可能并非如此)。

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

与其他声明相反,只有当流要转到文件(std::cin并且std::cout是特殊但静止的文件(或类似文件))时,n字符才会映射到正确的平台行尾序列。

可能存在

性能问题,std::endl强制刷新输出流。

如果你打算使用std::endl,这里隐含了另一个函数调用

a) std::cout << "Hellon";
b) std::cout << "Hello" << std::endl;

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

我记得在标准中读到过这个,所以这里是:

请参阅 C11 标准,

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

ISO/IEC 9899:201x

7.21.3 §7

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

7.21.3 §3

当流未缓冲时,字符旨在从源或 尽快到达目的地。否则可能会累积字符和 作为块传输到主机环境或从主机环境传输。当流完全缓冲时, 字符旨在作为块传输到主机环境或从主机环境传输,在以下情况下 填充缓冲区。当流被行缓冲时,字符应 当换行符 遇到。此外,字符旨在作为块传输到主机 填充缓冲区时的环境,在未缓冲的流上请求输入时,或 当在需要传输 主机环境中的字符。对这些特征的支持是 实现定义,并可能通过 setbuf 和 setvbuf 函数受到影响。

这意味着当且仅std::coutstd::cin引用非交互式设备时,它们才会完全缓冲。换句话说,如果 stdout 连接到终端,则行为没有区别。

但是,如果调用std::cout.sync_with_stdio(false),则'n'甚至不会导致交互设备刷新。否则'n'等效于std::endl除非管道到文件:std::endl 上的 c++ ref

它们都将写入适当的行尾字符。除此之外,endl 将导致提交缓冲区。在执行文件 I/O 时,通常不希望使用 endl,因为不必要的提交会影响性能。

没什么

大不了的,但endl在boost::lambda中不起作用。

(cout<<_1<<endl)(3); //error
(cout<<_1<<"n")(3); //OK , prints 3
如果你使用

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(这是正确的),显然在qtextstream.h(这是QtCore的一部分)中定义了endl函数。

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

从未见过有人说的是'n'受到cout格式的影响:

#include <iostream>
#include <iomanip>
int main() {
    std::cout << "\n:n" <<  std::setw(2) << std::setfill('0') << 'n';
    std::cout << "std::endl:n" << std::setw(2) << std::setfill('0') << std::endl;
}

输出:

n:
0
std::endl:

请注意,由于'n'是一个字符并且填充宽度设置为 2,因此在 'n' 之前只打印 1 个零。

我在任何地方都找不到关于它的任何信息,但它用 clang、gcc 和 msvc 重现。

当我第一次看到它时,我超级困惑。

附参考 这是一个仅输出的 I/O 操纵器

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

何时使用:

该机械手可用于立即产生输出线,

例如

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

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

来自 GCC 文档:

有些人还认为,向下发送输出流的 endl 只会写一个换行符。这是不正确的;写入换行符后,也会刷新缓冲区。也许这就是写入屏幕时想要的效果 - 尽快取出文本等 - 但是在对文件执行此操作时,缓冲在很大程度上被浪费了:

output << "a line of text" << endl;
output << some_data_variable << endl;
output << "another line of text" << endl; 

在这种情况下,正确的做法是将数据写出,让库和系统担心缓冲。如果您需要换行符,只需编写换行符:

output << "a line of textn"
<< some_data_variable << 'n'
<< "another line of textn"; 

您可以检查 ostream 的文档,或检查实现本身endl - 在我的案例中,usr/include/c++/11/ostream:684 - 。在那里你会发现:

  // Standard basic_ostream manipulators
  /**
   *  @brief  Write a newline and flush the stream.
   *
   *  This manipulator is often mistakenly used when a simple newline is
   *  desired, leading to poor buffering performance.  See
   *  https://gcc.gnu.org/onlinedocs/libstdc++/manual/streambufs.html#io.streambuf.buffering
   *  for more on this subject.
  */
  template<typename _CharT, typename _Traits>
    inline basic_ostream<_CharT, _Traits>&
    endl(basic_ostream<_CharT, _Traits>& __os)
    { return flush(__os.put(__os.widen('n'))); }