9

Tengo una duda con la función endl del manipulador de flujos.

Según el libro que estoy leyendo (Deitel), endl vacía el búfer de salida.

¿Qué quiere decir esto? Ya que si pongo "\n" o std::endl al final de cout recibo la misma salida.

¿Hay alguna manera de poder ver la diferencia?

OscarGarcia
  • 26,999
  • 3
  • 26
  • 61
FermatsTheorem
  • 327
  • 3
  • 6
  • esta pregunta, ya había sido respondida, igual aun que ya es viejo el post dejo la liga a ver si a alguien mas le sirve o se le resuelve la duda [Aquí](https://es.stackoverflow.com/questions/21817/para-que-sirve-y-como-se-limpia-el-buffer) – Samael Mar 13 '19 at 00:37
  • Aunque la respuesta marcada como correcta explica muy bien la diferencia entre usar o no `endl`, queda patente en el comentario *"Ese último ejemplo es mi duda. No entiendo la diferencia, ya que ambos códigos me dan el mismo resultado"* que la duda era la diferencia entre usar `\n` y `std::endl`, quedando la duda sin resolver, ya que *"El resultado visual es el mismo, pero cuando algún programa sea inestable por algún error se aconseja usar endl ya que libera el buffer y así forzar a imprimirlo"* no es una buena respuesta o explicación a la diferencia. – OscarGarcia Oct 14 '21 at 07:21

2 Answers2

12

endl es usado para generar salto de linea:

Hay alguna manera de poder ver la diferencia? para responder tu pregunta te dejo un ejemplo:

#include <iostream>
using namespace std;

int main() {
    // your code goes here
    std::cout<<"hola1" << std::endl; 
    std::cout<<"hola2" << std::endl; 

    std::cout<<"hola3"; 
    std::cout<<"hola4"; 
    return 0;
}

el resultado sera:

hola1
hola2
hola3hola4

notese que para hola3 y hola4 no se uso endl

endl tiene el mismo resultado que \n, la unica diferencia es que std::endl vacía el buffer de salida, y '\n' no lo hace, es decir si deseas forzar una salida. usa endl

el mismo ejemplo pero con \n:

#include <iostream>
    using namespace std;

    int main() {
        // your code goes here
        std::cout<<"hola1\n"; 
        std::cout<<"hola2\n"; 

        std::cout<<"hola3"; 
        std::cout<<"hola4"; 
        return 0;
    }
userStack
  • 6,330
  • 3
  • 20
  • 41
0

Lo que dicen en el texto que has leído es correcto y puedes leerlo también en cualquier documentación de std::endl:

Insert newline and flush

Inserts a new-line character and flushes the stream.

Its behavior is equivalent to calling os.put('\n') (or os.put(os.widen('\n')) for character types other than char), and then os.flush().

En castellano:

Inserta una nueva línea y vacía la memoria temporal

Inserta un carácter de nueva línea y vacía la memoria temporal del flujo de datos.

Su comportamiento es equivalente a llamar a os.put('\n') (o os.put(os.widen('\n')) para tipos de caracteres diferentes de char), y después a os.flush().

Hay que tener en cuenta que el sistema operativo implementa de diferente manera el flujo de datos que da salida al terminal del usuario que la salida a un flujo de datos a un archivo, una tubería hacia otra aplicación, etc.

De modo que en una aplicación normal con salida directa al terminal no podrías comprobar la diferencia entre vaciar la memoria temporal del flujo de datos y no hacerlo.

Para mostrarte la diferencia voy a usar el siguiente código:

#include <iostream>
#ifdef _WIN32
    #include <windows.h>
#else
    #include <unistd.h>
    #define Sleep(t) usleep(t * 1000000)
#endif // _WIN32

int main() {
    std::cout << "Comienzo" << std::endl;
    for (int i = 1; i <= 3; i++) {
        std::cout << "Iteración: " << i << "\n";
        Sleep(1);
    }
    for (int i = 1; i <= 3; i++) {
        std::cout << "Iteración: " << i << std::endl;
        Sleep(1);
    }
    std::cout << "Fin" << std::endl;
}

Al ejecutar el código normalmente (./pruebas) estamos enviando la salida estándar al terminal del usuario. No habrá ninguna diferencia entre usar std::endl o no porque el sistema operativo vaciará automáticamente la memoria temporal (buffer) en cuanto se encuentre un retorno del carro (\n).

Al ejecutar la aplicación enviando su salida a una tubería a una segunda aplicación (./pruebas | more) el sistema operativo no hará un vaciado automático la memoria temporal (buffer) al encontrar el carácter de retorno del carro, por lo que durante la impresión de las primeras tres iteraciones no aparecerá nada por pantalla porque todo se almacena en una memoria temporal de la corriente de datos que no se enviará a more para ser mostrado en el terminal del usuario hasta que se ejecute el primer std::endl.

Puedes ver aquí el efecto anteriormente explicado:

Ejecución de prueba


¿Qué ventajas o usos tienen "\n" y std::endl?

  • Ventaja de usar "\n":

    • Al escribir datos en un archivo, tubería o conexión TCP, se escribirán en bloque minimizando las operaciones de entrada/salida necesarias para llevar a cabo la tarea.
  • Ventajas de usar std::endl:

    • Al enviar texto al terminal del usuario es conveniente asegurarse que éste lee la información que acabamos de presentar. Aunque el sistema operativo vacíe la memoria intermedia automáticamente es posible que esa información no se muestre al usuario cuando hace uso de herramientas de mejoras de visualización como more, less, tail -f, cat, etc.

    • En una comunicación a través de una conexión TCP o UNIX te aseguras que el flujo de datos ha sido enviado (ojo, pero eso no significa que haya sido leído por el otro extremo).

OscarGarcia
  • 26,999
  • 3
  • 26
  • 61