当我可以使用换行符时,为什么要使用endl?

68

使用cout时,是否有理由使用endl而不是直接使用\n?我的C++书上说要使用endl,但我不明白为什么。是因为\n的支持不如endl广泛,还是我漏掉了什么重要的东西?


6
要明确的是,绝大多数情况下,您不应该使用 endl。请参见此答案和评论。 - ildjarn
请记住,在DOS/Windows平台上,行尾符为"\r\n",而在某些(所有?)Mac平台上则为裸的"\r"。 - PypeBros
6
@sylvainulg: 这并不是特别相关。将'\n'字符打印到文本流中时,它会自动转换为系统的行尾表示。就这个而言,'\n'std::endl没有区别(区别在于flush)。 (Mac平台从OSX开始是基于Unix的,使用'\n'标记行尾。) - Keith Thompson
@UncleBens:是的,但是std::cerr很容易被重定向到与std::cout不同的文件中。 - Keith Thompson
此链接还说明了何时使用刷新(\endl),以及仅使用\n的情况。http://programmers.stackexchange.com/questions/185064/using-a-stream-manipulator-endl-or-a-newline-escape-character-n - Ruchir
显示剩余2条评论
3个回答

87

endl'\n'附加到流中调用流上的flush()。所以

cout << x << endl;

等同于

cout << x << '\n';
cout.flush();

流可能使用内部缓冲区,在流刷新时实际进行流式传输。对于cout,您可能不会注意到差异,因为它与cin有一定的同步(绑定),但对于任意流,例如文件流,在多线程程序中您会注意到差异。
这里有一个有趣的讨论,解释了为什么刷新可能是必要的。点击这里

1
另外,endl不是会被转换为适当的平台换行符号(在Windows上为“\r\n”,在Linux上为“\n”)吗? - André Puel
7
C标准规定'\n'会自动转换为相应的字符。因此,是的,由于endl附加了一个'\n',这种情况正在发生。但这不仅适用于endl - Chad La Guardia
3
@Nawaz:避免晦涩和冗余,倡导阐明。 - Armen Tsirunyan
2
@Chad:是的——C++标准也是如此,这也是我们正在讨论的内容。 - Keith Thompson
1
@Keith:Stack Overflow 有一个问题:“用 C 可以做什么,而用 C++ 不行。”我的最爱答案之一是:“我可以用一只手轻松地举起带注释的 C 标准打印版1000次”。 - Armen Tsirunyan
显示剩余3条评论

7

endl 不仅仅是 \n 字符的别名。当你将某些东西发送到 cout(或任何其他输出流)时,它不会立即处理和输出数据。例如:

cout << "Hello, world!";
someFunction();

在上面的例子中,函数调用在输出被刷新之前有一些机会开始执行。使用 endl 强制在第二条指令执行之前进行刷新。您也可以使用 ostream::flush 函数确保刷新。

1
你的意思是“或者任何其他缓冲输出流”。 - ildjarn
为什么 someFunction() 在第一行之前就执行了?有什么可能导致这种情况发生? - DirichletIsaPartyPooper

-2

endl是一个函数而不是关键字。

#include <iostream>
int main()
{
 std::cout<<"Hello World"<<std::endl;  //endl is a function without parenthesis.
 return 0;
}   

要理解 endl 的概念,首先需要了解“函数指针”这个主题。
看一下这段 C 代码。
#include <stdio.h>
int add(int, int);
int main()
{
   int (*p)(int, int); /*p is a pointer variable which can store the address    
   of a function whose return type is int and which can take 2 int.*/
   int x;

   p=add;                     //Here add is a function without parenthesis.

   x=p(90, 10); /*if G is a variable and Address of G is assigned to p then     
   *p=10 means 10 is assigned to that which p points to, means G=10                        
   similarly x=p(90, 10); this instruction simply says that p points to add    
   function then arguments of p becomes arguments of add i.e add(90, 10)   
   then add function is called and sum is computed.*/  

   printf("Sum is %d", x);
   return 0;
}
int add(int p, int q)
{
  int r;
  r=p+q;
  return r;
}

编译此代码并查看输出。

回到主题...

 #include <iostream>
 //using namespace std; 
 int main()
 {
 std::cout<<"Hello World"<<std::endl;
 return 0;
 }

这个程序中包含了iostream文件,因为cout对象的原型在iostream文件中,并且std是一个命名空间。它被使用是因为cout和endl的定义(库文件)在命名空间std中; 或者你也可以在顶部使用"using namespace std",这样你就不必在每个cout或endl之前写"std::coutn<<....."。

当你不带括号写endl时,你将endl函数的地址传递给cout,然后调用endl函数并换行。 这背后的原因是

namespace endl
{
printf("\n");
}

结论:在C++的背后,是C代码在运行。

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