2016-06-23 12 views
9

Ich versuche, die libuv api und schrieb den folgenden Test zu lernen:Warum ist Stdout-Pufferung?

#include <stdio.h> 
#include <stdlib.h> 
#include <uv.h> 

void timer_cb(uv_timer_t* timer) { 
    int* i = timer->data; 
    --*i; 
    if(*i == 0) { 
     uv_timer_stop(timer); 
    } 
    printf("timer %d\n", *i); 
    //fflush(stdout); 
} 

int main() { 
    uv_loop_t* loop = uv_default_loop(); 
    uv_timer_t* timer = malloc(sizeof(uv_timer_t)); 
    uv_timer_init(loop, timer); 
    int i = 5; 
    timer->data = &i; 
    uv_timer_start(timer, timer_cb, 1000, 2000); 

    uv_run(loop, UV_RUN_DEFAULT); 

    printf("Now quitting.\n"); 
    uv_close(timer, 0); 
    uv_loop_close(loop); 

    return 0; 
} 

Wenn er gestartet wird es wird keine Ausgabe angezeigt, bis das Programm ausgeführt wird beendet, und dann wird die gesamte Ausgabe wird sofort angezeigt. Wenn ich die fflush Zeile auskommentiere, funktioniert es wie erwartet und schreibt alle 2 Sekunden.

Kann mir bitte jemand das erklären? Warum wird stdout nicht nach dem Newline gespült, wie es here und an anderen Stellen erklärt wird? Warum muss ich es manuell spülen?

+2

Was ist Ihr Betriebssystem? –

+2

"Warum ist Stdout-Pufferung" - Warum nicht? – Olaf

+0

Diese Antwort könnte nützlich für Sie sein: http://stackoverflow.com/a/5229135/868691 –

Antwort

13

Stream-Pufferung ist implementierungsdefiniert.

Per 7.21.3 Dateien Absatz 3 der C Standard:

Wenn ein Strom ist ungepufferte werden Zeichen von der Quelle erscheinen sollen oder am Ziel so schnell wie möglich. Andernfalls können die Zeichen akkumuliert und als Block an die Umgebung des Hosts übertragen werden. Wenn ein Stream vollständig gepuffert ist, sollen Zeichen als Block in die oder aus der Host-Umgebung übertragen werden, wenn ein Puffer gefüllt ist. Wenn ein Stream ist Zeile gepuffert, Zeichen sollen an oder von der Host-Umgebung als Block übertragen werden, wenn eine neue Zeile Zeichen auftritt. Außerdem sollen Zeichen als Block an die Host-Umgebung übertragen werden, wenn ein Puffer gefüllt ist, wenn eine Eingabe für einen ungepufferten Datenstrom angefordert wird oder wenn eine Eingabe für einen zeilengepufferten Datenstrom angefordert wird, der die Übertragung von Zeichen erfordert vom Host Umgebung. Unterstützung für diese Merkmale ist Implementierung definiert, und kann über die setbuf und setvbuf Funktionen beeinflusst werden.

Die Art der Pufferung hängt von Ihrer Implementierung ab, und Ihre Implementierung scheint in Ihrem Beispiel nicht die Zeilenpufferung zu verwenden.

+1

Ich legte es auf Zeilenpufferung mit 'setvbuf (stdout, NULL, _IOLBF, 0);' und es funktioniert immer noch nicht. Nur wenn ich es auf keine Pufferung ('_IONBF') setze, funktioniert es – baruch

+2

@baruch Diese Antwort interessiert Sie vielleicht - http://Stackoverflow.com/a/4027867/4756299 –

+1

Wie in dieser Antwort verknüpft, unter Windows gibt es keine Zeilenpufferung. Ich nehme an, dass das Problem ist https://msdn.microsoft.com/en-us/library/86cebhfs.aspx#Anchor_3 – baruch

5

Es gibt keine strenge Anforderung, dass stdout Zeile gepuffert ist. Es kann auch vollständig gepuffert sein (oder überhaupt nicht gepuffert sein), in welchem ​​Fall \n nicht auslöst, um den Strom zu spülen.

C11 (N1570) 7.21.3/7 Files:

Wie zunächst geöffnet, der Standard-Fehlerstrom nicht vollständig gepuffert; Die Standard-Eingangs- und Standard-Ausgangsströme sind vollständig gepuffert, wenn und nur dann, wenn der Datenstrom festgestellt werden kann, dass er sich nicht auf ein interaktives Gerät bezieht.

C11 (N1570) 5.1.2.3/7 Programmausführung:

Was ein interaktives Gerät bildet, ist die Implementierung definiert.

Sie könnten versuchen, bestimmte Art der Pufferung durch setvbuf Standard-Funktion zu erzwingen. Beispielsweise Linie Pufferung für stdout zu setzen, kann man versuchen, mit:

setvbuf(stdout, buff, _IOLBF, size); 

wo buff als Zeichen-Array von Elementen size deklariert wird (beispielsweise 1024).

Beachten Sie, dass setvbuf vor jeder anderen E/A-Operation aufgerufen werden muss, die für den Stream ausgeführt wird.

+0

Ich legte es auf Zeile Pufferung mit 'setvbuf (stdout, NULL, _IOLBF, 0);' und es funktioniert immer noch nicht. Nur wenn ich es auf keine Pufferung ('_IONBF') setze, funktioniert es – baruch

+0

@baruch: AFAIR,' setvbuf' benötigt, um es mit selbst vorbereiteten Puffer zu liefern. Andernfalls wird es nicht funktionieren. –

2

Aus irgendeinem Grund entscheidet Ihr System, dass Ihr stdout nicht interaktiv ist. Machst du eine seltsame Umleitung von stdout oder etwas komisches mit deinem Terminal? Sie sollten in der Lage sein, setbuf zu überschreiben, oder Sie können stderr anstelle von stdout verwenden.

+0

Dies liefert keine Antwort auf die Frage. Um einen Autor zu kritisieren oder um Klärung zu bitten, hinterlasse einen Kommentar unter seinem Beitrag. - [Aus Bewertung] (/ review/low-quality-posts/12787815) – StepUp

+0

Ich denke, es enthält 2 Antworten: Verwenden Sie Setvbuf oder Stderr. Die dritte Antwort wird nur impliziert, um herauszufinden, warum das System stdout für nicht interaktiv hält. – GroovyDotCom