C ++: "std :: endl" vs "\ n"
-
03-07-2019 - |
Pregunta
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 he visto un montón de código de desarrolladores que trabajan como este en su lugar:
std::cout << "Test line\n";
¿Hay una razón técnica para preferir una sobre la otra, o es solo una cuestión de estilo de codificación?
Solución
Los caracteres de final de línea variables no importan, asumiendo que el archivo está abierto en modo de texto, que es lo que obtienes a menos que solicites un binario. El programa compilado escribirá lo correcto para el sistema compilado para.
La única diferencia es que std :: endl
vacía el búfer de salida, y '\ n'
no lo hace. Si no desea que el búfer se vacíe con frecuencia, use '\ n'
. Si lo hace (por ejemplo, si desea obtener toda la salida y el programa es inestable), use std :: endl
.
Otros consejos
La diferencia se puede ilustrar con lo siguiente:
std::cout << std::endl;
es equivalente a
std::cout << '\n' << std::flush;
Entonces,
- Use
std :: endl
si desea forzar un vaciado inmediato a la salida. - Utilice
\ n
si está preocupado por el rendimiento (que probablemente no sea el caso si está utilizando el operador< <
).
Uso \ n
en la mayoría de las líneas.
Luego use std :: endl
al final de un párrafo (pero eso es solo un hábito y no suele ser necesario).
Al contrario de otras afirmaciones, el carácter \ n
se asigna a la secuencia correcta de fin de línea de la plataforma solo si la secuencia va a un archivo ( std :: cin
y std :: cout
son especiales pero archivos fijos (o como archivos)).
Puede haber problemas de rendimiento, std :: endl
obliga a una descarga de la secuencia de salida.
Recordé haber leído sobre esto en el estándar, así que aquí va:
Vea el estándar C11 que define cómo se comportan los flujos estándar, ya que los programas C ++ se interconectan con el 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 es necesario abrirlos explícitamente - Entrada estándar (para leer entrada convencional), salida estándar (para escritura salida convencional), y error estándar (para escribir salida de diagnóstico). Como inicialmente abierto, el flujo de error estándar no está completamente en búfer; La entrada estándar y estándar. los flujos de salida están completamente almacenados en búfer si y solo si se puede determinar que el flujo no haga referencia a un dispositivo interactivo.
7.21.3 §3
Cuando una secuencia no tiene buffer, se pretende que los caracteres aparezcan desde la fuente o en la Destino lo antes posible. De lo contrario los caracteres pueden ser acumulados y transmitido hacia o desde el entorno host como un bloque. Cuando una secuencia está completamente amortiguada, los caracteres deben transmitirse hacia o desde el entorno host como un bloque cuando se llena un búfer. Cuando una secuencia tiene búfer de línea, los caracteres están destinados a ser transmitido hacia o desde el entorno del host como un bloque cuando un carácter de nueva línea es encontrado. Además, los caracteres están destinados a ser transmitidos como un bloque al host ambiente cuando se llena un búfer, cuando se solicita la entrada en un flujo no almacenado en búfer, o cuando se solicita la entrada en una línea de transmisión en búfer que requiere la transmisión de personajes del entorno host. El soporte para estas características es definida por la implementación, y puede verse afectada a través de las funciones setbuf y setvbuf.
Esto significa que std :: cout
y std :: cin
están completamente almacenados en si y solo si se están refiriendo a un no dispositivo interactivo En otras palabras, si stdout se adjunta a un terminal, entonces no hay diferencia en el comportamiento.
Sin embargo, si se llama a std :: cout.sync_with_stdio (false)
, '\ n'
no causará una descarga ni siquiera a dispositivos interactivos. De lo contrario, '\ n'
es equivalente a std :: endl
a menos que se canalice a los archivos: c ++ ref on std :: endl .
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.
Ambos escribirán los caracteres de final de línea apropiados. Además de eso, endl hará que el búfer se confirme. Por lo general, no desea usar endl al hacer E / S de archivo porque las confirmaciones innecesarias pueden afectar el rendimiento.
No es un gran problema, pero endl no funcionará en boost :: lambda .
(cout<<_1<<endl)(3); //error
(cout<<_1<<"\n")(3); //OK , prints 3
Si usas Qt y endl, accidentalmente podrías usar el endl
incorrecto, me pasó hoy y era como ... WTF ??
#include <iostream>
#include <QtCore/QtCore>
#include <QtGui/QtGui>
//notice that i dont have a "using namespace std;"
int main(int argc, char** argv)
{
QApplication qapp(argc,argv);
QMainWindow mw;
mw.show();
std::cout << "Finished Execution !" << endl << "...";
// Line above printed: "Finished Execution !67006AB4..."
return qapp.exec();
}
Por supuesto que fue mi error, ya que debería haber escrito std :: endl
, pero si usa * endl
, qt y usando namespace std;
depende del orden de los archivos de inclusión si se utilizará el endl
correcto.
Por supuesto, puede volver a compilar Qt para usar un espacio de nombres, por lo que obtiene un error de compilación para el ejemplo anterior.
EDITAR: Se olvidó de mencionar, el endl
de Qt se declara en " qtextstream.h " que es parte de QtCore
* EDIT2: C ++ seleccionará el endl
correcto si tiene un usando
para std :: cout
o el espacio de nombres std
, dado que std :: endl
está en el mismo espacio de nombres que std :: cout
, el mecanismo ADL de C ++ seleccionará std :: endl
.
Siempre he tenido la costumbre de usar std :: endl porque me resulta fácil verlo.
Con referencia Esto es solo una salida Manipulador de E / S .
std::endl
Inserta un carácter de nueva línea en la secuencia de salida os y lo vacía como si llamara a os.put (os.widen ('\ n '))
seguido de os.flush ()
.
Cuándo usar:
Este manipulador se puede usar para producir una línea de salida inmediatamente ,
por ejemplo
cuando se muestra el resultado de un proceso de larga duración, la actividad de registro de varios subprocesos o la actividad de registro de un programa que puede fallar inesperadamente.
También
También es necesaria una descarga explícita de std :: cout antes de una llamada a std :: system, si el proceso generado realiza cualquier 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 de programa obliga a 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.
Si tiene la intención de ejecutar su programa en otra cosa que no sea su propia computadora portátil, nunca use la declaración endl
. Especialmente si está escribiendo muchas líneas cortas o porque a menudo he visto caracteres individuales en un archivo. El uso de endl
es conocido para eliminar sistemas de archivos en red como NFS.
El manipulador endl
es equivalente a '\'
. Pero endl
siempre descarga la secuencia.
std::cout << "Test line" << std::endl; // with flush
std::cout << "Test line\n"; // no flush
Si no se dio cuenta, endl
es como presionar la TECLA ENTER mientras que " \ n "
es como presionar ENTER KEY + BARRA ESPACIADORA.