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


569

Molti libri in C ++ contengono un esempio di codice come questo ...

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

... quindi l'ho sempre fatto anch'io. Invece ho visto molto codice da sviluppatori di lavoro come questo:

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

C'è un motivo tecnico per preferire l'uno rispetto all'altro, o è solo una questione di stile di codifica?




25
@derobert questo è più vecchio dell'altro
Kira,

3
@HediNaily lo è davvero. Ma la risposta sull'altro mi sembra leggermente migliore, quindi ho scelto di farlo in quel modo. Inoltre, l'altro è leggermente più ampio, coprendo anche '\n'.
derobert,

stackoverflow.com/a/30968225/3163618 potrebbe esserci una differenza di prestazioni significativa.
qwr

Risposte:


473

I vari caratteri di fine riga non contano, supponendo che il file sia aperto in modalità testo, che è quello che ottieni a meno che non richiedi il binario. Il programma compilato scriverà la cosa corretta per il sistema compilato.

L'unica differenza è che std::endlsvuota il buffer di output e '\n'non lo fa. Se non si desidera scaricare frequentemente il buffer, utilizzare '\n'. In tal caso (ad esempio, se si desidera ottenere tutto l'output e il programma è instabile), utilizzare std::endl.


24
Oppure prendere in considerazione l'utilizzo ::std::cerranziché il ::std::coutfatto che è senza buffer e svuotato con ogni singola operazione di output.
Onnipotente il

142
@Omnifario: No std :: cerr dovrebbe essere riservato per errori. I due flussi non sono sincronizzati insieme, quindi se si emette del testo per il cout potrebbe essere bufferizzato e il cerr andrà direttamente all'output con conseguente visualizzazione in modalità mista. Usa cerr per quello che dovrebbe essere (errori) e cout per quello per cui è progettato (normale interazione).
Martin York,

23
@Lucas: Non più di '\ n' è a conoscenza della piattaforma.
CB Bailey,

32
@LokiAstari: non direi stderr"errori". Piuttosto, è per i messaggi diagnostici fuori banda, se vuoi. Dovrebbe essere possibile dire ./prog > filee memorizzare solo il vero payload del programma, ma al programma potrebbe piacere di produrre molte più informazioni sullo stato, anche in interazione normale.
Kerrek SB,

13
"In molte implementazioni, l'output standard è bufferizzato in linea e la scrittura '\ n' causa comunque un flush, a meno che non sia stato eseguito std :: cout.sync_with_stdio (false)." copiato da qui
GuLearn

249

La differenza può essere illustrata da quanto segue:

std::cout << std::endl;

è equivalente a

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

Così,

  • Usa std::endlSe vuoi forzare un flush immediato all'output.
  • Utilizzare \nse si è preoccupati per le prestazioni (che probabilmente non è il caso se si utilizza l' <<operatore).

Uso la \nmaggior parte delle linee.
Quindi utilizzare std::endlalla fine di un paragrafo (ma è solo un'abitudine e di solito non è necessario).

Contrariamente ad altre affermazioni, il \npersonaggio è mappato alla sequenza di fine riga corretta della piattaforma solo se il flusso sta andando a un file ( std::cined std::coutè speciale ma è ancora file (o simile a un file)).


5
In molti casi, "vedi l'output immediatamente" è un'aringa rossa, poiché coutè legata cin, il che significa che se leggi l'input da cin, coutverrà eliminata per prima. Ma se vuoi visualizzare una barra di avanzamento o qualcosa senza leggere da cin, allora sicuramente è utile il flushing.
Chris Jester-Young,

9
@LokiAstari: se stai usando l'operatore <<, probabilmente non sei preoccupato per le prestazioni - perché? Non sapevo che operator<<non fosse performante o quale alternativa usare per la performance? Per favore, indicami del materiale per capirlo ulteriormente.
legends2k

8
@ legends2k: c'è una vecchia storia di mogli secondo cui i flussi C ++ non sono performanti come C printf (). Sebbene sia vero fino a un certo punto, la principale differenza di velocità è causata da persone che usano i flussi C ++ in modo errato. stackoverflow.com/a/1042121/14065 In C ++ ricordarsi di non sincronizzare gli iostreams con i flussi C sync_with_stdio(false)e non scaricare continuamente l'output. Lascia che la biblioteca decida quando farlo. stackoverflow.com/a/1926432/14065
Martin York,

6
@Loki: esiste una leggenda urbana che sync_with_stdiorende gli iostreams veloci come lo stdio. Non lo fa
Ben Voigt,

2
@BenVoigt: sono stato attento con le mie parole sopra (quindi sono contento di loro). Non è performante come lo stdio (perché fa di più). MA gran parte del gap prestazionale di cui le persone si lamentano è dovuto alla sincronizzazione con stdio.
Martin York,


30

C'è un'altra chiamata di funzione implicita lì se hai intenzione di usare std::endl

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

a) chiama l'operatore <<una volta.
b) chiama l'operatore <<due volte.


19
Può essere ovvio, ma ha un impatto enorme sui programmi thread in cui, in genere, la prima versione scriverà una singola riga in uno scatto in cui la seconda versione può essere divisa da scritture da altri thread. Abbastanza spesso mi ritrovo a scrivere std :: cout << "ciao \ n" << std :: flush per evitare questo.
smparkes,

Che dire std::cout << "Hello" << "\n";?
byxor,

1
@byxor Quasi lo stesso tranne lo svuotamento del buffer come descritto in altre risposte. Ad ogni modo, è ridondante quando è possibile unire i due letterali stringa in uno solo.
iBug

Bene, se la stringa da stampare non è letterale, allora anche le chiamate a <<sarebbero 2 nel caso a , quindi non pretenderei che la necessità di una o due <<(o due chiamate di funzione in generale) sia una differenza tra \ne endl.
Enrico Maria De Angelis,

Lol no, non è questo il motivo per cui uso \ n.
Carlo Wood,

28

Ho ricordato di averlo letto nello standard, quindi ecco:

Vedi lo standard C11 che definisce come si comportano i flussi standard, poiché i programmi C ++ interfacciano il CRT, lo standard C11 dovrebbe governare qui la politica di lavaggio.

ISO / IEC 9899: 201x

7.21.3 §7

All'avvio del programma, tre flussi di testo sono predefiniti e non devono essere aperti in modo esplicito: input standard (per la lettura dell'input convenzionale), output standard (per la scrittura dell'output convenzionale) ed errore standard (per la scrittura dell'output diagnostico). Come inizialmente aperto, il flusso di errori standard non è completamente bufferizzato; i flussi di input standard e output standard sono completamente bufferizzati se e solo se il flusso può essere determinato in modo da non fare riferimento a un dispositivo interattivo.

7.21.3 §3

Quando uno stream è senza buffer, i personaggi devono apparire dalla fonte o dalla destinazione il più presto possibile. Altrimenti i caratteri possono essere accumulati e trasmessi da o verso l'ambiente host come blocco. Quando uno stream è completamente bufferizzato, i caratteri devono essere trasmessi da o verso l'ambiente host come un blocco quando viene riempito un buffer. Quando uno stream ha un buffer di linea, i caratteri devono essere trasmessi da o verso l'ambiente host come un blocco quando viene rilevato un carattere di nuova riga. Inoltre, i caratteri devono essere trasmessi come blocco all'ambiente host quando viene riempito un buffer, quando viene richiesto l'input su un flusso senza buffer o quando viene richiesto l'input su un flusso con buffer di linea che richiede la trasmissione di caratteri dall'ambiente host .

Ciò significa che std::coute std::cinsono completamente tamponati se e solo se essi si riferiscono a un dispositivo non interattiva. In altre parole, se stdout è collegato a un terminale, non vi è alcuna differenza nel comportamento.

Tuttavia, se std::cout.sync_with_stdio(false)viene chiamato, '\n'non causerà un flush anche per i dispositivi interattivi. Altrimenti '\n'equivale a std::endlmeno che non si esegua il piping ai file: c ++ ref su std :: endl .


19

Entrambi scriveranno i caratteri di fine riga appropriati. Oltre a questo endl, verrà eseguito il commit del buffer. Di solito non si desidera utilizzare endl quando si esegue l'I / O dei file perché i commit non necessari possono influire sulle prestazioni.



10

Se usi Qt e endl, potresti accidentalmente finire con un errore endlche ti dà risultati molto sorprendenti. Vedi il seguente frammento di codice:

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

Si noti che ho scritto endlinvece std::endl(che sarebbe stato corretto) e apparentemente c'è una endlfunzione definita in qtextstream.h (che fa parte di QtCore).

L'utilizzo "\n"anziché endleludere completamente eventuali problemi dello spazio dei nomi. Questo è anche un buon esempio del perché mettere simboli nello spazio dei nomi globale (come fa Qt per impostazione predefinita) è una cattiva idea.


31
Urgh! Chi vorrebbe mai essere using namespace std;? :-)
Steve Folly,

2
Cattiva. Grazie per il commento, sono sicuro che altri lo troveranno.
Head Geek,

@SteveFolly Lo faccio. Perchè no?
ʇolɐǝz ǝɥʇ qoq

@ ʇolɐǝzǝɥʇqoq Va bene finché non lo fai nei file di intestazione.
smerlin,

1
@ ʇolɐǝzǝɥʇqoq Per favore, evita using namespace std;. È considerata una cattiva pratica. Vedi Perché "usa lo spazio dei nomi std;" considerata cattiva pratica?
LF

2

Ho sempre avuto l'abitudine di usare solo std :: endl perché è facile per me vedere.


2

Il std::endlmanipolatore è equivalente a '\n'. Ma std::endlscarica sempre il flusso.

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

1

Se hai intenzione di eseguire il tuo programma su qualcosa di diverso dal tuo laptop, non utilizzare mai la endldichiarazione. Soprattutto se stai scrivendo molte righe brevi o come ho visto spesso singoli caratteri in un file. L'uso di endlè noto per eliminare i file system in rete come NFS.


Ciò è dovuto al lavaggio? Vedo come potrebbe essere possibile.
Head Geek,

@Head Indeed. L'ho visto anche rovinare le prestazioni IO del disco.
sabato

0

Con riferimento Questo è un manipolatore I / O di sola uscita .

std::endlInserisce un carattere di nuova riga nel sistema operativo della sequenza di output e lo svuota come chiamando chiamando os.put(os.widen('\n'))seguito da os.flush().

Quando usare:

Questo manipolatore può essere utilizzato per produrre immediatamente una riga di output ,

per esempio

quando si visualizza l'output di un processo a esecuzione prolungata, l'attività di registrazione di più thread o l'attività di registrazione di un programma che potrebbe arrestarsi in modo imprevisto.

Anche

Un esplicito flush di std :: cout è anche necessario prima di una chiamata a std :: system, se il processo generato esegue qualsiasi I / O dello schermo. Nella maggior parte degli altri scenari di I / O interattivi usuali, std :: endl è ridondante se utilizzato con std :: cout perché qualsiasi input da std :: cin, output in std :: cerr o terminazione del programma forza una chiamata a std :: cout .sciacquone(). L'uso di std :: endl al posto di '\ n', incoraggiato da alcune fonti, può degradare significativamente le prestazioni di output.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.