2016-06-23 20 views
9

Sto cercando di imparare la libuv api e ha scritto il seguente test:Perché il buffer stdout?

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

Quando viene eseguito, nessun output viene visualizzato fino a quando il programma termina l'esecuzione, e poi tutto l'output viene visualizzato in una sola volta. Se disattivi la linea fflush, funziona come previsto, scrivendo ogni 2 secondi.

Qualcuno può spiegarmi questo per favore? Perché lo stdout non viene svuotato dopo la nuova riga, come spiegato here e in altri luoghi? Perché ho bisogno di svuotarlo manualmente?

+2

Qual è il tuo sistema operativo? –

+2

"Perché è il buffering stdout" - Perché no? – Olaf

+0

Questa risposta può essere utile per te: http://stackoverflow.com/a/5229135/868691 –

risposta

13

Il buffering del flusso è definito dall'implementazione.

Per 7.21.3 Files, comma 3, del C Standard:

Quando un flusso è unbuffered, i personaggi sono destinati a comparire dalla sorgente o destinazione nel più breve tempo possibile. In alternativa, i caratteri possono essere accumulati e trasmessi dall'ambiente host o come host. Quando uno stream è completamente bufferizzato, i caratteri devono essere trasmessi da o verso l'ambiente host come blocco quando viene riempito un buffer. Quando un flusso è con buffer di linea, i caratteri devono essere trasmessi da o verso l'ambiente host come blocco quando viene rilevato un carattere di nuova riga. Inoltre, i caratteri devono essere trasmessi come blocco all'ambiente host quando un buffer è riempito , quando l'input è richiesto su un flusso non bufferizzato, o quando è richiesto l'input su un flusso bufferizzato di linea che richiede la trasmissione di caratteri dall'ambiente host . Il supporto per queste caratteristiche è definito dall'implementazione e potrebbe essere interessato dalle funzioni setbuf e setvbuf.

Il tipo di buffering dipende dall'implementazione e l'implementazione apparentemente non è il buffer di linea nell'esempio.

+1

L'ho impostato per il buffering di riga con 'setvbuf (stdout, NULL, _IOLBF, 0);' e ancora non funziona. Solo se l'ho impostato su nessun buffer ('_IONBF') funziona – baruch

+2

@baruch Questa risposta potrebbe essere rilevante - http://stackoverflow.com/a/4027867/4756299 –

+1

Come collegato in quella risposta, su Windows non c'è buffer di linea. Presumo che sia il problema https://msdn.microsoft.com/en-us/library/86cebhfs.aspx#Anchor_3 – baruch

5

Non esiste un requisito rigoroso, ovvero stdout è in modalità linea bufferizzata. Può anche essere completamente bufferizzato (o non bufferizzato affatto), nel qual caso \n non viene attivato per lo svuotamento del flusso.

C11 (N1570) 7.21.3/7 Files:

Come inizialmente aperto, il flusso di errore standard non è completamente tamponata; gli stream standard di input e output standard sono completamente bufferizzati se e solo se è possibile determinare lo stream in modo che non faccia riferimento a un dispositivo interattivo .

C11 (N1570) 5.1.2.3/7 esecuzione del programma:

Ciò che costituisce un dispositivo interattivo dipende dall'implementazione.

Si potrebbe provare a forzare un tipo specifico di buffer tramite la funzione standard setvbuf. Ad esempio, per impostare il buffering linea per stdout, si può provare con:

setvbuf(stdout, buff, _IOLBF, size); 

dove buff viene dichiarata come array di caratteri di size elementi (ad esempio 1024).

Si noti che setvbuf deve essere chiamato prima di qualsiasi altra operazione di I/O, eseguita sul flusso.

+0

L'ho impostato su buffer di riga con 'setvbuf (stdout, NULL, _IOLBF, 0);' e ancora non funziona. Solo se l'ho impostato su nessun buffer ('_IONBF') funziona – baruch

+0

@baruch: AFAIR,' setvbuf' richiede di fornirgli un buffer auto-preparato. Altrimenti, non funzionerà. –

2

Per qualche motivo, il tuo sistema sta decidendo che il tuo stdout non è interattivo. Stai facendo qualche strano reindirizzamento di stdout o stai facendo qualcosa di strano con il tuo terminale? Dovresti essere in grado di eseguire l'override usando setbuf oppure puoi usare stderr invece di stdout.

+0

Questo non fornisce una risposta alla domanda. Per criticare o richiedere chiarimenti da un autore, lascia un commento sotto il loro post. - [Dalla recensione] (/ recensione/post di bassa qualità/12787815) – StepUp

+0

Penso che includa 2 risposte: usa setvbuf o stderr. La terza risposta è solo implicita, per capire perché il sistema sta scambiando stdout per non interattivo. – GroovyDotCom

Problemi correlati