C ++: "std :: endl" vs "\ n"


569

Muchos libros de C ++ contienen código de ejemplo como este ...

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

... así que siempre he hecho eso también. Pero en cambio, he visto mucho código de desarrolladores que trabajan como este:

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

¿Hay alguna razón técnica para preferir uno sobre el otro, o es solo una cuestión de estilo de codificación?




25
@derobert este es más viejo que el otro
Kira

3
@HediNaily de hecho lo es. Pero la respuesta del otro me parece un poco mejor, así que elegí hacerlo de esa manera. Además, el otro es un poco más amplio, también cubre '\n'.
derobert

stackoverflow.com/a/30968225/3163618 puede haber una diferencia de rendimiento significativa.
qwr

Respuestas:


473

Los distintos caracteres de final de línea no importan, suponiendo que el archivo esté abierto en modo texto, que es lo que obtienes a menos que pidas un binario. El programa compilado escribirá lo correcto para el sistema compilado.

La única diferencia es que std::endlvacía el búfer de salida y '\n'no lo hace. Si no desea que el búfer se vacíe con frecuencia, úselo '\n'. Si lo hace (por ejemplo, si desea obtener toda la salida y el programa es inestable), use std::endl.


24
O considere usarlo en ::std::cerrlugar de hacerlo, ::std::coutya que no tiene búfer y se vacía con todas y cada una de las operaciones de salida.
Omnifarioso

142
@Omnifarious: No std :: cerr debe reservarse para errores. Las dos secuencias no se sincronizan juntas, por lo que si envía algo de texto a Cout, se puede almacenar en búfer y el cerr irá directamente a la salida, lo que dará como resultado una pantalla de modo mixto. Use cerr para lo que se supone que es (errores) y cout para lo que está diseñado (interacción normal).
Martin York

23
@Lucas: No más de '\ n' es consciente de la plataforma.
CB Bailey

32
@LokiAstari: No diría que stderres por "errores". Más bien, es para mensajes de diagnóstico fuera de banda, si lo desea. Debería ser posible decir ./prog > filey almacenar solo la carga útil real del programa, pero al programa le gustaría generar mucha más información de estado, incluso en una interacción normal.
Kerrek SB

13
"En muchas implementaciones, la salida estándar tiene un buffer de línea, y escribir '\ n' causa un vaciado de todos modos, a menos que se ejecute std :: cout.sync_with_stdio (false)". copiado de aquí
GuLearn

249

La diferencia puede ilustrarse con lo siguiente:

std::cout << std::endl;

es equivalente a

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

Entonces,

  • Use std::endlSi desea forzar un vaciado inmediato a la salida.
  • Úselo \nsi le preocupa el rendimiento (que probablemente no sea el caso si está utilizando el <<operador).

Yo uso \nen la mayoría de las líneas.
Luego usastd::endl al final de un párrafo (pero eso es solo un hábito y generalmente no es necesario).

Contrariamente a otras afirmaciones, el \ncarácter se asigna a la secuencia correcta de final de línea de la plataforma solo si la secuencia va a un archivo ( std::ciny std::coutes especial pero todavía archivos (o similar a un archivo )).


55
En muchos casos, el "ver la salida de inmediato" es una pista falsa, ya que coutestá vinculado a cin, lo que significa que si lee la entrada de cin, coutse eliminará primero. Pero si desea mostrar una barra de progreso o algo sin leer cin, entonces, seguro, el vaciado es útil.
Chris Jester-Young

99
@LokiAstari: si está utilizando el operador <<, probablemente no le preocupe el rendimiento , ¿por qué? No sabía que eso operator<<no es eficiente, ¿o qué alternativa usar para el rendimiento? Por favor, muéstrame algún material para entender esto más a fondo.
legends2k

8
@ legends2k: Hay una vieja historia de esposas que dice que los flujos de C ++ no son tan eficaces como C printf (). Aunque es cierto hasta cierto punto, la principal diferencia en la velocidad es causada por personas que usan transmisiones C ++ incorrectamente. stackoverflow.com/a/1042121/14065 En C ++, recuerde desincronizar iostreams con C-streams sync_with_stdio(false)y no vacíe su salida continuamente. Deje que la biblioteca determine cuándo hacerlo. stackoverflow.com/a/1926432/14065
Martin York

66
@Loki: Hay una leyenda urbana que sync_with_stdiohace que iostreams sea tan rápido como stdio. No lo hace
Ben Voigt

2
@BenVoigt: tuve cuidado con mi redacción anterior (así que estoy contento con ellos). No es tan eficiente como stdio (porque hace más). PERO gran parte de la brecha de rendimiento de la que se queja la gente es causada por la sincronización con stdio.
Martin York


30

Hay otra función llamada implícita allí si vas a usar std::endl

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

a) llama al operador <<una vez.
b) llama al operador <<dos veces.


19
Puede ser obvio, pero tiene un gran impacto en los programas de subprocesos donde, en general, la primera versión escribirá una sola línea de una sola vez, donde la segunda versión se puede dividir por las escrituras de otros hilos. A menudo me encuentro escribiendo std :: cout << "hello \ n" << std :: flush para evitar esto.
smparkes

¿Qué hay de std::cout << "Hello" << "\n";?
byxor

1
@byxor Casi lo mismo, excepto el lavado del búfer como se describe en otras respuestas. De todos modos, es redundante cuando puedes fusionar los dos literales de cadena en uno.
iBug

Bueno, si la cadena que se va a imprimir no es literal, entonces las llamadas al <<2 también serían en el caso a , por lo que no afirmaría que la necesidad de una o dos <<(o dos llamadas de función en general) sea un diferencia entre \ny endl.
Enrico Maria De Angelis

Lol no, esa no es la razón por la que uso \ n.
Carlo Wood

28

Recordé haber leído sobre esto en el estándar, así que aquí va:

Consulte el estándar C11 que define cómo se comportan las transmisiones estándar, ya que los programas C ++ interactúan con la CRT, el estándar C11 debe regir la política de descarga aquí.

ISO / IEC 9899: 201x

7.21.3 §7

Al inicio del programa, tres flujos de texto están predefinidos y no necesitan abrirse explícitamente: entrada estándar (para leer la entrada convencional), salida estándar (para escribir la salida convencional) y error estándar (para escribir la salida de diagnóstico). Como se abrió inicialmente, el flujo de error estándar no está completamente protegido; las secuencias de entrada y salida estándar están totalmente almacenadas si solo se puede determinar que la secuencia no se refiere a un dispositivo interactivo.

7.21.3 §3

Cuando una secuencia no tiene búfer, los caracteres deben aparecer desde el origen o en el destino lo antes posible. De lo contrario, los caracteres pueden acumularse y transmitirse hacia o desde el entorno host como un bloque. Cuando una secuencia está completamente almacenada en búfer, los caracteres están destinados a ser transmitidos hacia o desde el entorno host como un bloque cuando se llena un búfer. Cuando una secuencia tiene un buffer de línea, los caracteres están destinados a ser transmitidos hacia o desde el entorno host como un bloque cuando se encuentra un carácter de nueva línea. Además, los caracteres están destinados a ser transmitidos como un bloque al entorno host cuando se llena un búfer, cuando se solicita la entrada en un flujo sin búfer, o cuando se solicita la entrada en un flujo con búfer de línea que requiere la transmisión de caracteres desde el entorno del host .

Esto significa que std::couty std::cinestán plenamente compensados si y sólo si se están refiriendo a un dispositivo no interactivo. En otras palabras, si stdout está conectado a un terminal, entonces no hay diferencia en el comportamiento.

Sin embargo, si std::cout.sync_with_stdio(false)se llama, entonces '\n'no provocará una descarga incluso en dispositivos interactivos. De '\n'lo contrario, es equivalente a std::endlmenos que se canalice a los archivos: c ++ ref en std :: endl .


19

Ambos escribirán los caracteres de final de línea apropiados. Además de eso, endl hará que se confirme el búfer. Por lo general, no desea usar endl al hacer E / S de archivo porque las confirmaciones innecesarias pueden afectar el rendimiento.



10

Si usa Qt y endl, podría terminar accidentalmente usando un incorrecto endlque le da resultados muy sorprendentes. Consulte el siguiente fragmento de código:

#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();
}

Tenga en cuenta que escribí en endllugar de std::endl(lo que habría sido correcto) y aparentemente hay una endlfunción definida en qtextstream.h (que es parte de QtCore).

El uso en "\n"lugar de endleludir por completo cualquier posible problema de espacio de nombres. Este también es un buen ejemplo de por qué poner símbolos en el espacio de nombres global (como Qt lo hace por defecto) es una mala idea.


31
Urgh! ¿Quién querría ser alguna vez using namespace std;? :-)
Steve Folly

2
Asqueroso. Gracias por el comentario, estoy seguro de que otros se encontrarán con eso.
Head Geek

@SteveFolly que hago. Por qué no?
ʇolɐǝz ǝɥʇ qoq

@ ʇolɐǝzǝɥʇqoq Está bien siempre que no lo haga en los archivos de encabezado.
smerlin

1
@ ʇolɐǝzǝɥʇqoq Por favor, evite using namespace std;. Se considera una mala práctica. Consulte ¿Por qué está "usando el espacio de nombres estándar?" considerado una mala práctica?
LF


2

El std::endlmanipulador es equivalente a '\n'. Pero std::endlsiempre descarga la corriente.

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

1

Si tiene la intención de ejecutar su programa en otra cosa que no sea su propia computadora portátil, nunca use la endldeclaración. Especialmente si está escribiendo muchas líneas cortas o como he visto caracteres individuales en un archivo. El uso de endles saber matar sistemas de archivos en red como NFS.


¿Eso se debe al enrojecimiento? Puedo ver cómo podría ser posible.
Head Geek

@Head De hecho. También lo he visto destruir el rendimiento del disco IO.
sbi

0

Con referencia Este es un manipulador de E / S de solo salida .

std::endlInserta un carácter de nueva línea en la secuencia de salida os y lo vacía como si llamara os.put(os.widen('\n'))seguido de os.flush().

Cuándo usar:

Este manipulador puede usarse para producir una línea de salida inmediatamente ,

p.ej

cuando se muestra la salida de un proceso de larga ejecución, se registra la actividad de varios subprocesos o se registra la actividad de un programa que puede bloquearse inesperadamente.

también

También es necesario un vaciado explícito de std :: cout antes de una llamada a std :: system, si el proceso generado realiza alguna E / S de pantalla. En la mayoría de los otros escenarios de E / S interactivos habituales, std :: endl es redundante cuando se usa con std :: cout porque cualquier entrada de std :: cin, salida a std :: cerr o terminación del programa fuerza una llamada a std :: cout .rubor(). El uso de std :: endl en lugar de '\ n', alentado por algunas fuentes, puede degradar significativamente el rendimiento de salida.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.