2017-03-08 6 views
5

Ich lese ‚UNIX Network Programming: Die Sockets Networking API‘ und im Beispielcode haben sie eine Fehlerbehandlung Funktion, die die folgenden Zeilen enthält:Warum sollte ich fflush auf stdout verwenden, bevor ich in stderr schreibe?

fflush(stdout);  /* in case stdout and stderr are the same */ 
fputs(buf, stderr); 
fflush(stderr); 

Wo buf die Fehlerbeschreibung enthält. Ich verstehe nicht, warum fflush auf stdout in der ersten Zeile verwendet wird und warum der Kommentar den Grund für seine Verwendung erklärt.

Antwort

11

Dies ist wegen der Pufferung. Stdout and stderr are usually buffered differently. Stdout ist normalerweise Zeile gepuffert, was bedeutet, dass es keine Ausgabe anzeigen wird, bis es einen Zeilenumbruch sieht. Stderr ist in der Regel ungepuffert und wird sofort drucken, das Denken ist, sollten Sie Fehlermeldungen pronto sehen.

Aber sie beide gehen an den gleichen Ort, das Terminal. Dies ist, was es von /* in case stdout and stderr are the same */ bedeutet. Sie sind normalerweise. Da sie jedoch unterschiedlich gepuffert sind, kann dies dazu führen, dass sie nicht mehr angezeigt werden.

Betrachten Sie diesen Code. Beachten Sie das Fehlen von Zeilenumbrüchen.

#include <stdio.h> 

int main() { 
    fprintf(stdout, "This is to stdout. "); 
    fprintf(stderr, "This is to stderr. "); 
    fprintf(stdout, "This is also to stdout. "); 
} 

würden Sie die Ausgabe erwarten zu sein:

This is to stdout. This is to stderr. This is also to stdout. 

Aber es ist nicht. Es ist defekt.

$ ./test 
This is to stderr. This is to stdout. This is also to stdout. 

Die Ausgabe an stderr wird sofort angezeigt, es ist ungepuffert. Während stdout warten muss, bis der stdout-Puffer von einem newline gelöscht wird. Es gibt keine neue Zeile, daher wird es beim Beenden des Programms geleert.

Indem Sie stdout spülen, bevor Sie stderr verwenden, stellen Sie sicher, dass die Ausgabe unabhängig von der Pufferung in der richtigen Reihenfolge erfolgt.

#include <stdio.h> 
#include <unistd.h> 

int main() { 
    fprintf(stdout, "This is to stdout. "); 
    fflush(stdout); 
    fprintf(stderr, "This is to stderr. "); 
    fprintf(stdout, "This is also to stdout. "); 
} 

$ ./test 
This is to stdout. This is to stderr. This is also to stdout. 

Dies stellt sicher, dass Fehlermeldungen in der richtigen Reihenfolge zusammen mit normalen Nachrichten ausgegeben werden. Dies vermeidet Verwirrung darüber, welche Fehlermeldung für welchen Teil des Programms gilt.

+0

Ihr zweites Beispiel ist falsch; 'Dies soll auch zu Stande kommen.' Und 'Das soll zu Stande kommen. 'Sollte geschaltet werden. – Qix

+0

Wenn 'stderr' uncharakteristisch _line_ gepuffert war, würden ähnliche Probleme auftreten, die durch diese Antwort nicht behoben werden. Spüle den anderen vor dem Schreiben pedantisch. Oder verwenden Sie gute Etikette und [spülen Sie sobald Sie fertig sind] – chux

+1

@Qix Danke. Ich hatte ursprünglich die Dateihandles im Code gemischt. – Schwern

1

Wenn stdout und stderr auf die gleiche Datei zeigen, müssen Sie sicherstellen, dass alles, was im stdout-Puffer ist, zuerst geschrieben wird.