I am trying to learn the libuv
api and wrote the following test:
#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;
}
When run it, no output is displayed until the program finishes running, and then all the output is displayed at once. If I uncomment the fflush
line it works as expected, writing every 2 seconds.
Can someone please explain this to me? Why is stdout
not flushed after the newline, as is explained here and in other places? Why do I need tomanually flush it?
Stream buffering is implementation-defined.
Per 7.21.3 Files, paragraph 3 of the C Standard:
When a stream is
unbuffered, characters are intended to appear from the source or at the destination as soon as possible. Otherwise characters
may be accumulated and transmitted to or from the host
environment as a block. When a stream is
fully buffered, characters are intended to be transmitted to or from the host environment as a block when a buffer is filled. When a
stream is
line buffered, characters are intended to be transmitted to or from the host environment as a block when a new-line
character is encountered. Furthermore, characters are intended to be
transmitted as a block to the host environment when a buffer is
filled, when input is requested on an unbuffered stream, or when
input is requested on a line buffered stream that requires
the transmission of characters from the host
environment. Support for these characteristics is
implementation-defined, and may be affected via the setbuf
and
setvbuf
functions.
The type of buffering is dependent on your implementation, and your implementation apparently isn't line-buffering in your example.
There is no strict requirement, that stdout
is line buffered. It may be fully buffered as well (or not buffered at all), in which case \n
does not trigger to flush the stream.
C11 (N1570) 7.21.3/7 Files:
As initially opened, the standard error stream is not fully buffered;
the standard input and standard output streams are fully buffered if
and only if the stream can be determined not to refer to an
interactive device.
C11 (N1570) 5.1.2.3/7 Program execution:
What constitutes an interactive device is implementation-defined.
You could try to force specific type of buffering by setvbuf
standard function. For instance, to set line buffering for stdout
, you may try with:
setvbuf(stdout, buff, _IOLBF, size);
where buff
is declared as character array of size
elements (e.g. 1024).
Note that setvbuf
has to be called before any other I/O operation, that is performed to the stream.
For some reason, your system is deciding that your stdout is not interactive. Are you doing some strange redirect of stdout or doing something weird with your terminal? You should be able to override using setbuf or you can use stderr instead of stdout.