Para que serve o ENDL em C++? 2 exemplos comentados

Para que serve o ENDL em C++ com um botão enter para representar a quebra de linha

Acredito que em algum ponto na nossa trajetória na programação com essa linguagem, a maioria de nós já se fez a seguinte pergunta: “Para que serve o ENDL em C++?”. Se assim como eu você começou na programação em C++ com o famoso exemplo do “Hello World!” (espero que não tenham te traumatizado com ponteiros logo de cara), talvez você também tenha se perguntado para que servia o ENDL no fim daquela linha de código.

Muitos pensam que o end serve apenas para adicionar uma quebra ao final de uma linha, mas na verdade esse é o papel do caractere ‘\n’. O ENDL em C++ serve para “pular uma linha” no que está sendo impresso na tela (ou em arquivo de texto, por exemplo). Ele adiciona um caractere de quebra de linha (como o ‘\n’) ao final do fluxo de saída e também serve para descarregar esse fluxo de saída (ou para fazer um flush, em inglês), fazendo com que seu conteúdo seja mostrado na tela imediatamente (no caso do cout, por exemplo).

Fluxos de saída em C++

Um fluxo de saída é qualquer objeto que derive da classe basic_ostream (da biblioteca padrão std). Esses objetos permitem realizar operações de “saída” sobre fluxos de caracteres (imprimir frases na tela, escrever algo em um arquivo de log etc.). Os objeto mais conhecido desse tipo é o cout, disponível no header <iostream>, mas também há outros que podem ser usados da mesma maneira, como o cerr (para imprimir mensagens de erro) e o clog (para logs do sistema).

Diferença entre o \n e o ENDL em C++

A diferença entre o caractere de quebra de linha (\n) e o ENDL é bastante simples: o ENDL adiciona um \n no final do fluxo de saída, mas ele também faz com que o fluxo de saída seja descarregado imediatamente; ao usar apenas o \n, não há garantia de que o que se escreve no cout, por exemplo, através do operador << será exibido na tela imediatamente. Apesar disso, algumas implementações fazem com que o \n também cause uma descarga do fluxo de saída, de modo tal que utilizar endl desnecessariamente pode degradar a performance do sistema (pois o endl insere un \n além de realizar uma descarga ‘manual’).

Exemplo de uso do ENDL em C++

Vejamos abaixo um exemplo de uso do endl em um programa simples que mede o tempo decorrido entre as iterações de um laço for (o exemplo é baseado no exemplo do Cpp Reference).

/**********************************************
* Para que serve o ENDL em C++?
* Exemplo #1
**********************************************/

#include <iostream>
#include <chrono>
 
int main()
{
    int acumulador = 0;
    
    // t1 guarda a hora no início da execução do primeiro for
    auto t1 = std::chrono::high_resolution_clock::now();
    for (int j=0; j<5; ++j)
    {
        for (int n=0; n<10000; ++n)
            for (int m=0; m<20000; ++m)
                acumulador += m*n; // realiza cálculos apenas para passar o tempo
        auto now = std::chrono::high_resolution_clock::now();
        auto deltaT = now - t1; // tempo decorrido desde o início do laço externo até agora
        std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(deltaT).count()
              << " ms se passaram desde o fim da última iteração" << std::endl;
    }
}

9323 ms se passaram desde o fim da última iteração
15220 ms se passaram desde o fim da última iteração
15978 ms se passaram desde o fim da última iteração
16862 ms se passaram desde o fim da última iteração
17666 ms se passaram desde o fim da última iteração

No exemplo acima, na linha 23, o tempo decorrido entre o início do programa e o fim de cada iteração é imprimido na tela usando cout, e ele é seguido pela sentença “ms se passaram desde o fim da última iteração”. Esse valor é impresso 5 vezes, como vemos no bloco de resultado anterior.

A diferença entre ter usado endl e apenas \n na linha 23 do exemplo #1 é a seguinte: se eu tivesse usado \n, eu não teria garantia de que cada mensagem seria mostrada na tela assim que o cout da linha 23 fosse executado – poderia acontecer que todas as 5 linhas de saída se “acumulassem” no cout e só fossem mostradas na tela ao final da execução do for mais externo de todos.

Forma equivalente usando \n e flush()

hand flushing toilet

Para se garantir que o texto seja mostrado na tela imediatamente após a escrita usando cout e \n (ao invés de ENDL, que aliás deve ser evitado sempre que possível, para garantir que não ocorram descargas desnecessárias nos fluxos de saída, o que pode degradar a performance do sistema), podemos combinar o \n com o método flush() que se aplica sobre os fluxos de saída.

/**********************************************
* Para que serve o ENDL em C++?
* Exemplo #2 - \n e flush
**********************************************/

#include <iostream>
#include <chrono>
 
int main()
{
    int acumulador = 0;
    
    // t1 guarda a hora no início da execução do primeiro for
    auto t1 = std::chrono::high_resolution_clock::now();
    for (int j=0; j<5; ++j)
    {
        for (int n=0; n<10000; ++n)
            for (int m=0; m<20000; ++m)
                acumulador += m*n; // realiza cálculos apenas para passar o tempo
        auto now = std::chrono::high_resolution_clock::now();
        auto deltaT = now - t1; // tempo decorrido desde o início do laço externo até agora
        std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(deltaT).count()
              << " ms se passaram desde o fim da última iteração\n";
        std::cout.flush();
    }
}

3073 ms se passaram desde o fim da última iteração
5893 ms se passaram desde o fim da última iteração
9218 ms se passaram desde o fim da última iteração
12369 ms se passaram desde o fim da última iteração
15470 ms se passaram desde o fim da última iteração

* Os resultados foram sendo mostrados um por um, imediatamente após a execução de cada cout

O método flush() mostrado no exemplo anterior força a descarga do fluxo de saída. Assim sendo, ele garante que o texto seja imediatamente mostrado na tela. Todavia, é de se imaginar que usá-lo muito frequentemente pode ter um custo no tempo de execução do programa. Logo, o melhor é, sempre que possível, utilizar apenas o \n se o seu objetivo for apenas obter uma quebra de linha no fluxo de saída.

Bons hábitos – #1 Use \n ao invés de ENDL em C++ sempre que possível

O uso desnecessário do endl pode acarretar custos desnecessários à performance do programa. Logo, é uma boa idéia utilizar \n ao invés de endl se seu objetivo for apenas obter uma quebra de linha.

Conclusão

Neste artigo vimos para que serve o ENDL em C++, além de vermos qual é a diferença entre o seu uso e o uso do caractere \n. Ademais, vimos também como obter um resultado equivalente ao do uso do ENDL através da combinação \n e flush().

Foto de perfil de Emanoel

Sou apaixonado por tecnologia, literatura e também filosofia. O cultivo dessas paixões ao longo da minha trajetória me inspiraram a compartilhar aquilo que aprendo com os outros da maneira mais clara que eu possa. Sou formado em Engenharia Elétrica no Brasil, e também sou engenheiro formado na França. Trabalho atualmente como programador C++ em uma multinacional francesa, uma das maiores empresas de TI do mundo.

Leave a Reply

Your email address will not be published. Required fields are marked *