2016-06-23 4 views
9

Я пытаюсь узнать libuv апи и написал следующий тест:Почему буферизация 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; 
} 

При запуске его вывод не отображается, пока программа не завершит работу, а затем все выходные сразу отображается. Если я раскомментирую линию fflush, она работает как ожидается, записывая каждые 2 секунды.

Может кто-нибудь, пожалуйста, объясните мне это? Почему stdout не покраснел после новой строки, как объясняется here и в других местах? Зачем мне нужно ручно его смывать?

+2

Какая у вас ОС? –

+2

«Почему буферизация stdout» - Почему нет? – Olaf

+0

Этот ответ может быть вам полезен: http://stackoverflow.com/a/5229135/868691 –

ответ

13

Буферизация потока определяется реализацией.

Per 7.21.3 Файлы пункта 3 C Standard:

Когда поток небуферизован, символы предназначены появляться из источника или пункта назначения как можно скорее. В противном случае символы могут накапливаться и передаваться в среду или на хост в качестве блока. Когда поток полностью буферизирован, символы предназначены для передачи в или из среды хоста в виде блока при заполнении буфера. Когда поток равен строка буферизирована, символы предназначены для передачи в или из среды хоста в виде блока при знаком новой строки . Кроме того, символы должны быть , переданные в качестве блока в среду хоста, когда буфер заполнен , если запрос запрашивается в небуферизованном потоке или когда запрашивается вход в потоке с линейной буферизацией, для которой требуется передача символов от хоста окружающая среда. Поддержка этих характеристик , определяемая реализацией, и может быть затронута функциями setbuf и setvbuf.

Тип буферизации зависит от вашей реализации, и ваша реализация, по-видимому, не является буферизацией строки в вашем примере.

+1

Я установил его для буферизации строк с помощью 'setvbuf (stdout, NULL, _IOLBF, 0);' и он все еще не работает. Только если я настроил его на отсутствие буферизации ('_IONBF'), он работает – baruch

+2

@baruch Этот ответ может быть уместным - http://stackoverflow.com/a/4027867/4756299 –

+1

Как указано в этом ответе, в Windows нет буферизация строк. Я предполагаю, что это проблема https://msdn.microsoft.com/en-us/library/86cebhfs.aspx#Anchor_3 – baruch

5

Не существует строгих требований, что stdout является буферизированной линией. Он может быть полностью забуферирован (или вообще не буферизирован), и в этом случае \n не вызывает сброс потока.

С11 (N1570) 7.21.3/7 Файлы:

Как первоначально открыт, стандартный поток ошибок не полностью буферном; стандартные входные и стандартные выходные потоки полностью буферизуются, если и только если можно определить поток, чтобы не ссылаться на интерактивное устройство .

C11 (N1570) 5.1.2.3/7 Выполнение программы:

Что представляет собой интерактивное устройство определяется реализацией.

Вы можете попытаться настроить определенный тип буферизации на стандартную функцию setvbuf. Например, чтобы установить буферизацию линии для stdout, вы можете попробовать с:

setvbuf(stdout, buff, _IOLBF, size); 

где buff объявлен как символьный массив size элементов (например, 1024).

Обратите внимание, что setvbuf необходимо вызывать перед любой другой операцией ввода-вывода, которая выполняется в потоке.

+0

Я установил ее для буферизации строк с помощью 'setvbuf (stdout, NULL, _IOLBF, 0);' и он все еще не работает. Только если я настроил его на отсутствие буферизации ('_IONBF'), он работает – baruch

+0

@baruch: AFAIR,' setvbuf' требует, чтобы он снабжал его самоподготовленным буфером. В противном случае это не сработает. –

2

По какой-то причине ваша система решает, что ваша стандартная версия не является интерактивной. Вы делаете странную переадресацию stdout или делаете что-то странное с вашим терминалом? Вы можете переопределить использование setbuf или использовать stderr вместо stdout.

+0

Это не дает ответа на вопрос. Чтобы критиковать или просить разъяснения у автора, оставьте комментарий ниже их сообщения. - [Из обзора] (/ review/low-quality-posts/12787815) – StepUp

+0

Я думаю, что он включает в себя 2 ответа: используйте setvbuf или stderr. Третий ответ подразумевается только для того, чтобы понять, почему система ошибочно принимала stdout для неинтерактивных. – GroovyDotCom