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


569

Muitos livros em C ++ contêm código de exemplo como este ...

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

... então eu sempre fiz isso também. Mas já vi muito código de desenvolvedores trabalhando como este:

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

Existe um motivo técnico para preferir um ao outro, ou é apenas uma questão de estilo de codificação?




25
@derobert este é mais velho do que o outro
Kira

3
@HediNaily de fato é. Mas a resposta do outro me parece um pouco melhor, então escolhi fazê-lo dessa maneira. Além disso, o outro é um pouco mais amplo, também cobrindo '\n'.
derobert

stackoverflow.com/a/30968225/3163618 pode haver uma diferença significativa de desempenho.
qwr 24/03

Respostas:


473

Os caracteres de final de linha variados não importam, supondo que o arquivo esteja aberto no modo de texto, que é o que você obtém, a menos que você peça binário. O programa compilado escreverá a coisa correta para o sistema compilado.

A única diferença é que std::endllibera o buffer de saída e '\n'não. Se você não deseja que o buffer seja liberado com freqüência, use '\n'. Se você o fizer (por exemplo, se quiser obter toda a saída e o programa for instável), use std::endl.


24
Ou considere usar em ::std::cerrvez de, ::std::coutuma vez que é sem buffer e liberado a cada operação de saída.
Onívoro

142
@ Omnifarious: Não std :: cerr deve ser reservado para erros. Os dois fluxos não são sincronizados juntos; portanto, se você enviar algum texto para o cout, ele poderá ser armazenado em buffer e o cerr irá direto para a saída, resultando em uma exibição em modo misto. Use cerr para o que deveria ser (erros) e cout para o que foi projetado (interação normal).
Martin York

23
@ Lucas: Não mais do que '\ n' reconhece a plataforma.
CB Bailey

32
@LokiAstari: Eu não diria que stderré por "erros". Pelo contrário, é para mensagens de diagnóstico fora da banda, se você desejar. Deveria ser possível dizer ./prog > filee armazenar apenas a verdadeira carga útil do programa, mas o programa pode gostar de gerar muito mais informações de status, mesmo em interação normal.
31411 Kerrek SB

13
"Em muitas implementações, a saída padrão é armazenada em buffer de linha, e escrever '\ n' causa uma descarga de qualquer maneira, a menos que std :: cout.sync_with_stdio (false) tenha sido executado." copiado daqui
GuLearn 13/13

249

A diferença pode ser ilustrada pelo seguinte:

std::cout << std::endl;

é equivalente a

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

Assim,

  • Use std::endlSe você deseja forçar uma descarga imediata na saída.
  • Use \nse estiver preocupado com o desempenho (o que provavelmente não é o caso se você estiver usando o <<operador).

Eu uso \nna maioria das linhas.
Em seguida, use std::endlno final de um parágrafo (mas isso é apenas um hábito e geralmente não é necessário).

Ao contrário de outras reivindicações, o \ncaractere é mapeado para a sequência correta de fim de linha da plataforma somente se o fluxo estiver indo para um arquivo ( std::cine std::coutsendo especial, mas ainda arquivos (ou semelhantes a arquivos)).


5
Em muitos casos, o "veja a saída imediatamente" é um arenque vermelho, pois coutestá vinculado a cin, o que significa que, se você ler a entrada de cin, coutserá liberado primeiro. Mas se você deseja exibir uma barra de progresso ou algo sem ler a partir cin, é claro que a descarga é útil.
Chris Jester-Young

9
@LokiAstari: se você estiver usando o operador <<, provavelmente não está preocupado com o desempenho - por quê? Eu não sabia que operator<<não tinha desempenho ou que alternativa usar para o desempenho? Por favor, aponte-me para algum material para entender melhor isso.
legends2k

8
@ legends2k: Há um velho conto de mulheres que os fluxos de C ++ não são tão eficientes quanto C printf (). Embora seja verdade até certo ponto, a principal diferença de velocidade é causada por pessoas que usam fluxos C ++ incorretamente. stackoverflow.com/a/1042121/14065 No C ++, lembre-se de dessincronizar iostreams com fluxos C sync_with_stdio(false)e não libere sua saída continuamente. Deixe a biblioteca decidir quando fazê-lo. stackoverflow.com/a/1926432/14065
Martin York

6
@Loki: Existe uma lenda urbana que sync_with_stdiotorna os iostreams tão rápidos quanto o stdio. Não
Ben Voigt

2
@BenVoigt: Tomei cuidado com minha redação acima (então estou feliz com eles). Não é tão eficiente quanto o stdio (porque faz mais). MAS grande parte da lacuna de desempenho que as pessoas reclamam é causada pela sincronização com o stdio.
Martin York


30

Há outra chamada de função implícita lá, se você for usar std::endl

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

a) chama o operador <<uma vez.
b) chama o operador <<duas vezes.


19
Pode ser óbvio, mas tem um enorme impacto em programas encadeados, onde, geralmente, a primeira versão grava uma única linha em uma cena em que a segunda versão pode ser dividida por gravações de outros encadeamentos. Frequentemente, eu me pego escrevendo std :: cout << "olá \ n" << std :: flush para evitar isso.
smparkes

Que tal std::cout << "Hello" << "\n";?
byxor

1
@byxor Quase o mesmo, exceto a descarga do buffer, conforme descrito em outras respostas. De qualquer forma, é redundante quando você pode mesclar os dois literais de seqüência de caracteres em um.
iBug

Bem, se a string a ser impressa não for literal, as chamadas para o <<seriam também 2 no caso a , portanto, eu não reivindicaria a necessidade de uma ou duas <<(ou duas chamadas de função em geral). diferença entre \ne endl.
Enrico Maria De Angelis

Lol não, não é por isso que eu uso \ n.
Carlo Wood

28

Lembrei-me de ler sobre isso no padrão, então aqui vai:

Consulte o padrão C11, que define como os fluxos padrão se comportam. Como os programas C ++ fazem interface com a CRT, o padrão C11 deve governar a política de liberação aqui.

ISO / IEC 9899: 201x

7.21.3 §7

Na inicialização do programa, três fluxos de texto são predefinidos e não precisam ser abertos explicitamente - entrada padrão (para leitura de entrada convencional), saída padrão (para gravação de saída convencional) e erro padrão (para gravação de saída de diagnóstico). Como aberto inicialmente, o fluxo de erro padrão não é totalmente armazenado em buffer; os fluxos de entrada e saída padrão são totalmente armazenados em buffer se, e somente se, o fluxo puder ser determinado para não se referir a um dispositivo interativo.

7.21.3 §3

Quando um fluxo não é armazenado em buffer, os caracteres devem aparecer da origem ou do destino o mais rápido possível. Caso contrário, os caracteres podem ser acumulados e transmitidos para ou do ambiente host como um bloco. Quando um fluxo é totalmente armazenado em buffer, os caracteres devem ser transmitidos para ou a partir do ambiente host como um bloco quando um buffer é preenchido. Quando um fluxo é buffer de linha, os caracteres devem ser transmitidos para ou do ambiente host como um bloco quando um caractere de nova linha é encontrado. Além disso, os caracteres devem ser transmitidos como um bloco para o ambiente host quando um buffer é preenchido, quando a entrada é solicitada em um fluxo sem buffer ou quando a entrada é solicitada em um fluxo com buffer de linha que requer a transmissão de caracteres do ambiente host. .

Isso significa que std::coute std::cinsão totalmente armazenados em buffer se, e somente se , estiverem se referindo a um dispositivo não interativo. Em outras palavras, se stdout estiver conectado a um terminal, não haverá diferença no comportamento.

No entanto, se std::cout.sync_with_stdio(false)for chamado, '\n'não causará descarga mesmo em dispositivos interativos. Caso contrário, '\n'é equivalente a std::endlmenos que o canal seja feito para os arquivos: c ++ ref on std :: endl .


19

Ambos escreverão os caracteres de final de linha apropriados. Além desse endl, o buffer será confirmado. Você geralmente não deseja usar endl ao executar E / S de arquivo, porque as confirmações desnecessárias podem afetar o desempenho.



10

Se você usa Qt e endl, você pode acidentalmente acabar usando um incorreto, o endlque fornece resultados muito surpreendentes. Veja o seguinte trecho 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();
}

Observe que eu escrevi em endlvez de std::endl(o que estaria correto) e, aparentemente, há uma endlfunção definida em qtextstream.h (que faz parte do QtCore).

Usar em "\n"vez de endlevitar completamente qualquer possível problema de espaço para nome. Este também é um bom exemplo de por que colocar símbolos no espaço para nome global (como o Qt faz por padrão) é uma má idéia.


31
Urgh! Quem iria querer ser using namespace std;? :-)
Steve Folly

2
Desagradável. Obrigado pelo comentário, tenho certeza que outros irão encontrar isso.
Head Geek

@SteveFolly eu faço. Por que não?
ʇolɐǝz ǝɥʇ qoq

@ ʇolɐǝzǝɥʇqoq Tudo bem desde que você não faça isso nos arquivos de cabeçalho.
smerlin

1
@ ʇolɐǝzǝɥʇqoq Por favor, evite using namespace std;. É considerado uma má prática. Consulte Por que "usar o namespace std;" considerada má prática?
LF

2

Eu sempre tive o hábito de usar apenas std :: endl porque é fácil para mim ver.


2

O std::endlmanipulador é equivalente a '\n'. Mas std::endlsempre libera o fluxo.

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

1

Se você pretende executar seu programa em qualquer outra coisa que não seja o seu próprio laptop, nunca use a endlinstrução. Especialmente se você estiver escrevendo muitas linhas curtas ou como eu já vi caracteres únicos em um arquivo. O uso de endlé conhecido por eliminar sistemas de arquivos em rede como o NFS.


Isso é devido à descarga? Eu posso ver como isso pode ser possível.
Chefe Geek

@ Head De fato. Eu também vi destruindo o desempenho de E / S do disco.
Sf # 519

0

Com referência Este é um manipulador de E / S somente de saída .

std::endlInsere um caractere de nova linha na sequência de saída os e libera-o como se chamando os.put(os.widen('\n'))seguido de os.flush().

Quando usar:

Este manipulador pode ser usado para produzir uma linha de saída imediatamente ,

por exemplo

ao exibir a saída de um processo de longa execução, atividade de log de vários threads ou atividade de log de um programa que pode travar inesperadamente.

Além disso

Uma liberação explícita de std :: cout também é necessária antes de uma chamada para std :: system, se o processo gerado executar qualquer E / S de tela. Na maioria dos outros cenários usuais de E / S interativa, std :: endl é redundante quando usado com std :: cout porque qualquer entrada de std :: cin, saída para std :: cerr ou terminação de programa força uma chamada para std :: cout .rubor(). O uso de std :: endl no lugar de '\ n', incentivado por algumas fontes, pode prejudicar significativamente o desempenho da saída.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.