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

569

Viele C ++ - Bücher enthalten Beispielcode wie diesen ...

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

... also habe ich das auch immer gemacht. Aber ich habe stattdessen viel Code von arbeitenden Entwicklern wie diesen gesehen:

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

Gibt es einen technischen Grund, einen dem anderen vorzuziehen, oder ist es nur eine Frage des Codierungsstils?

Head Geek
quelle
1
mögliches Duplikat von "\ n" oder '\ n' oder std :: endl zu std :: cout?
Derobert
25
@derobert dieser ist älter als der andere
Kira
3
@ HediNaily in der Tat ist es. Aber die Antwort auf die andere Frage scheint mir etwas besser zu sein, also habe ich mich dafür entschieden, es so zu machen. Auch der andere ist etwas breiter und bedeckt ebenfalls '\n'.
Derobert
Bei stackoverflow.com/a/30968225/3163618 kann es zu erheblichen Leistungsunterschieden kommen.
qwr

Antworten:

473

Die unterschiedlichen Zeichen am Zeilenende spielen keine Rolle, vorausgesetzt, die Datei ist im Textmodus geöffnet. Dies erhalten Sie, wenn Sie nicht nach Binärdateien fragen. Das kompilierte Programm schreibt das Richtige für das kompilierte System aus.

Der einzige Unterschied besteht darin, dass std::endlder Ausgabepuffer geleert wird und '\n'nicht. Wenn Sie nicht möchten, dass der Puffer häufig geleert wird, verwenden Sie '\n'. Wenn Sie dies tun (z. B. wenn Sie die gesamte Ausgabe erhalten möchten und das Programm instabil ist), verwenden Sie std::endl.

David Thornley
quelle
24
Oder verwenden Sie ::std::cerrstatt, ::std::coutda es bei jeder Ausgabeoperation ungepuffert und geleert ist.
Omnifarious
142
@ Omnifarious: Kein std :: cerr sollte für Fehler reserviert werden. Die beiden Streams werden nicht miteinander synchronisiert. Wenn Sie also Text an cout ausgeben, wird dieser möglicherweise gepuffert, und der cerr geht direkt zur Ausgabe, was zu einer Anzeige im gemischten Modus führt. Verwenden Sie cerr für das, wofür es gedacht ist (Fehler) und cout für das, wofür es entwickelt wurde (normale Interaktion).
Martin York
23
@Lucas: Nicht mehr als '\ n' ist plattformbewusst.
CB Bailey
32
@LokiAstari: Ich würde nicht sagen, stderrist für "Fehler". Wenn Sie so wollen, handelt es sich eher um Out-of-Band-Diagnosemeldungen. Es sollte möglich sein, ./prog > filenur die wahre Programmnutzlast zu sagen und zu speichern, aber das Programm möchte möglicherweise auch bei normaler Interaktion viel mehr Statusinformationen ausgeben.
Kerrek SB
13
"In vielen Implementierungen ist die Standardausgabe zeilengepuffert, und das Schreiben von '\ n' führt ohnehin zu einem Flush, es sei denn, std :: cout.sync_with_stdio (false) wurde ausgeführt." von hier kopiert
GuLearn
249

Der Unterschied kann durch Folgendes veranschaulicht werden:

std::cout << std::endl;

ist äquivalent zu

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

Damit,

  • Verwendung std::endlWenn Sie eine sofortige Spülung des Ausgangs erzwingen möchten.
  • Verwenden \nSie diese Option, wenn Sie sich Sorgen um die Leistung machen (was wahrscheinlich nicht der Fall ist, wenn Sie den <<Operator verwenden).

Ich benutze \nauf den meisten Linien.
Verwenden Sie dann std::endlam Ende eines Absatzes (aber das ist nur eine Gewohnheit und normalerweise nicht notwendig).

Im Gegensatz zu anderen Behauptungen wird das \nZeichen nur dann dem richtigen Ende der Zeilenfolge der Plattform zugeordnet, wenn der Stream zu einer Datei wechselt ( std::cinund std::coutspezielle, aber immer noch Dateien (oder dateiähnlich) sind).

Martin York
quelle
5
In vielen Fällen „sieht die Ausgabe sofort“ die eine falsche Fährte ist, da coutzu gebunden ist cin, was bedeutet , dass , wenn Sie eine Eingabe von gelesen cin, coutwird zunächst gespült werden. Wenn Sie jedoch einen Fortschrittsbalken oder etwas anzeigen möchten, ohne davon zu lesen cin, ist das Spülen sicher hilfreich.
Chris Jester-Young
9
@LokiAstari: Wenn Sie den Operator << verwenden, machen Sie sich wahrscheinlich keine Sorgen um die Leistung - warum? Ich wusste nicht, dass operator<<das nicht performant ist, oder welche Alternative für die Performance? Bitte verweisen Sie mich auf Material, um dies besser zu verstehen.
Legends2k
8
@ legends2k: Es gibt eine alte Frauengeschichte, dass C ++ - Streams nicht so performant sind wie C printf (). Obwohl dies in gewissem Maße zutrifft, wird der Hauptunterschied in der Geschwindigkeit dadurch verursacht, dass Benutzer C ++ - Streams falsch verwenden. stackoverflow.com/a/1042121/14065 Denken Sie in C ++ daran, iostreams mit C-Streams zu synchronisieren sync_with_stdio(false)und Ihre Ausgabe nicht kontinuierlich zu leeren . Lassen Sie die Bibliothek herausfinden, wann dies zu tun ist. stackoverflow.com/a/1926432/14065
Martin York
6
@Loki: Es gibt eine urbane Legende, sync_with_stdiodie iostreams so schnell wie stdio macht. Es tut nicht
Ben Voigt
2
@ BenVoigt: Ich war vorsichtig mit meinem obigen Wortlaut (also bin ich mit ihnen zufrieden). Es ist nicht so performant wie stdio (weil es mehr kann). ABER ein Großteil der Leistungslücke, über die sich die Leute beschweren, ist auf die Synchronisierung mit stdio zurückzuführen.
Martin York
40

Möglicherweise treten Leistungsprobleme auf, std::endlwodurch ein Löschen des Ausgabestreams erzwungen wird.

Martin Beckett
quelle
1
Und es kann jede andere Verarbeitung ausführen, die das lokale System benötigt, damit dies gut funktioniert.
dmckee --- Ex-Moderator Kätzchen
30

Dort ist ein weiterer Funktionsaufruf enthalten, wenn Sie ihn verwenden möchten std::endl

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

a) ruft den Betreiber <<einmal an.
b) ruft den Betreiber <<zweimal an.

Nathan
quelle
19
Es mag offensichtlich sein, aber es hat einen großen Einfluss auf Thread-Programme, bei denen im Allgemeinen die erste Version eine einzelne Zeile auf einmal schreibt, wobei die zweite Version durch Schreibvorgänge von anderen Threads aufgeteilt werden kann. Oft genug schreibe ich std :: cout << "hallo \ n" << std :: flush, um dies zu vermeiden.
smparkes
Was ist mit std::cout << "Hello" << "\n";?
bis zum
1
@byxor Fast das gleiche, außer dass der Puffer geleert wird, wie in anderen Antworten beschrieben. Auf jeden Fall ist es überflüssig, wenn Sie die beiden Zeichenfolgenliterale zu einem zusammenführen können.
iBug
Nun, wenn die zu druckende Zeichenfolge kein Literal ist, dann <<wären die Aufrufe von the auch in dem Fall a 2 , daher würde ich nicht behaupten, dass ein oder zwei <<(oder zwei Funktionsaufrufe im Allgemeinen) a erforderlich sind Unterschied zwischen \nund endl.
Enrico Maria De Angelis
Lol nein, das ist nicht der Grund, warum ich \ n benutze.
Carlo Wood
28

Ich erinnerte mich daran, dass ich im Standard darüber gelesen hatte.

Siehe C11-Standard, der definiert, wie sich die Standard-Streams verhalten, da C ++ - Programme die CRT verbinden. Der C11-Standard sollte hier die Spülrichtlinie regeln.

ISO / IEC 9899: 201x

7.21.3 §7

Beim Programmstart sind drei Textströme vordefiniert und müssen nicht explizit geöffnet werden - Standardeingabe (zum Lesen herkömmlicher Eingaben), Standardausgabe (zum Schreiben herkömmlicher Ausgaben) und Standardfehler (zum Schreiben diagnostischer Ausgaben). Beim ersten Öffnen ist der Standardfehlerstrom nicht vollständig gepuffert. Die Standardeingabe- und Standardausgabestreams werden genau dann vollständig gepuffert, wenn festgestellt werden kann, dass sich der Stream nicht auf ein interaktives Gerät bezieht.

7.21.3 §3

Wenn ein Stream ungepuffert ist, sollen Zeichen so schnell wie möglich von der Quelle oder vom Ziel angezeigt werden. Andernfalls können Zeichen akkumuliert und als Block zur oder von der Hostumgebung übertragen werden. Wenn ein Stream vollständig gepuffert ist, sollen Zeichen als Block zur oder von der Host-Umgebung übertragen werden, wenn ein Puffer gefüllt ist. Wenn ein Stream zeilengepuffert ist, sollen Zeichen als Block zur oder von der Host-Umgebung übertragen werden, wenn ein neues Zeilenzeichen auftritt. Darüber hinaus sollen Zeichen als Block an die Host-Umgebung übertragen werden, wenn ein Puffer gefüllt ist, wenn eine Eingabe in einem ungepufferten Stream angefordert wird oder wenn eine Eingabe in einem zeilengepufferten Stream angefordert wird, der die Übertragung von Zeichen aus der Host-Umgebung erfordert .

Dies bedeutet, dass std::coutund std::cingenau dann vollständig gepuffert werden, wenn sie sich auf ein nicht interaktives Gerät beziehen. Mit anderen Worten, wenn stdout an ein Terminal angeschlossen ist, gibt es keinen Unterschied im Verhalten.

Wenn dies std::cout.sync_with_stdio(false)jedoch aufgerufen wird, '\n'wird auch bei interaktiven Geräten kein Flush verursacht. Andernfalls '\n'entspricht dies dem std::endlWeiterleiten an Dateien: c ++ ref on std :: endl .

Emily L.
quelle
19

Sie schreiben beide die entsprechenden Zeilenendezeichen. Zusätzlich dazu wird durch endl der Puffer festgeschrieben. Normalerweise möchten Sie endl nicht verwenden, wenn Sie Datei-E / A ausführen, da die unnötigen Festschreibungen die Leistung beeinträchtigen können.

Ferruccio
quelle
10

Wenn Sie Qt und verwenden endl, könnten Sie versehentlich ein falsches verwenden endl, was zu sehr überraschenden Ergebnissen führt. Siehe den folgenden Codeausschnitt:

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

Beachten Sie, dass ich endlanstelle von std::endl(was richtig gewesen wäre) geschrieben habe und anscheinend eine endlFunktion in qtextstream.h definiert ist (die Teil von QtCore ist).

Verwenden Sie potenzielle Namespace-Probleme, "\n"anstatt sie endlvollständig zu umgehen. Dies ist auch ein gutes Beispiel dafür, warum das Einfügen von Symbolen in den globalen Namespace (wie dies Qt standardmäßig tut) eine schlechte Idee ist.

Smerlin
quelle
31
Urgh! Wer würde jemals sein wollen using namespace std;? :-)
Steve Folly
2
Böse. Vielen Dank für den Kommentar, ich bin sicher, dass andere darauf stoßen werden.
Head Geek
@SteveFolly mache ich. Warum nicht?
ʇolɐǝz ǝɥʇ qoq
@ ʇolɐǝzǝɥʇqoq Es ist in Ordnung, solange Sie dies nicht in Header-Dateien tun.
Smerlin
1
@ ʇolɐǝzǝɥʇqoq Bitte vermeiden using namespace std;. Es wird als schlechte Praxis angesehen. Siehe Warum wird der Namespace std verwendet? als schlechte Praxis angesehen?
LF
2

Ich hatte immer die Angewohnheit, nur std :: endl zu verwenden, weil es für mich leicht zu sehen ist.

Zee JollyRoger
quelle
2

Der std::endlManipulator entspricht '\n'. std::endlSpült aber immer den Strom.

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

Wenn Sie beabsichtigen, Ihr Programm auf etwas anderem als Ihrem eigenen Laptop auszuführen, verwenden Sie die endlAnweisung niemals . Vor allem, wenn Sie viele kurze Zeilen schreiben oder wie ich oft einzelne Zeichen in einer Datei gesehen habe. Die Verwendung von endlist bekannt, um vernetzte Dateisysteme wie NFS zu töten.

John Damm Sørensen
quelle
Liegt das an der Spülung? Ich kann sehen, wie es möglich sein könnte.
Head Geek
@ Kopf in der Tat. Ich habe auch gesehen, dass es die Leistung der Festplatten-E / A beeinträchtigt.
sbi
0

Mit Referenz Dies ist ein E / A-Manipulator nur für die Ausgabe .

std::endlFügt ein Zeilenumbruchzeichen in die Ausgabesequenz os ein und löscht es wie durch Aufrufen os.put(os.widen('\n'))gefolgt von os.flush().

Wann zu verwenden:

Dieser Manipulator kann verwendet werden , um eine Linie von produzieren sofort ausgegeben ,

z.B

Wenn Sie die Ausgabe eines lang laufenden Prozesses anzeigen, die Aktivität mehrerer Threads protokollieren oder die Aktivität eines Programms protokollieren, das möglicherweise unerwartet abstürzt.

Ebenfalls

Ein explizites Leeren von std :: cout ist auch vor einem Aufruf von std :: system erforderlich, wenn der erzeugte Prozess eine Bildschirm-E / A ausführt. In den meisten anderen üblichen interaktiven E / A-Szenarien ist std :: endl bei Verwendung mit std :: cout redundant, da jede Eingabe von std :: cin, Ausgabe an std :: cerr oder Programmbeendigung einen Aufruf von std :: cout erzwingt .spülen(). Die Verwendung von std :: endl anstelle von '\ n', die von einigen Quellen empfohlen wird, kann die Ausgabeleistung erheblich beeinträchtigen.

Kaleem Ullah
quelle