The important background here is that
stdout is required to be line buffered by the standard as default setup.
This causes a
\n to flush the output.
Since the second example does not contain the newline, the output is not flushed and as
fork() copies the whole process, it also copies the state of the
fork() calls in your example create 8 processes in total - all of them with a copy of the state of the
By definition, all these processes call
exit() when returning from
fflush() followed by
fclose() on all active stdio streams. This includes
stdout and as a result, you see the same content eight times.
It is good practice to call
fflush() on all streams with pending output before calling
fork() or to let the forked child call explicitly
_exit() that only exits the process without flushing the stdio streams.
Note that calling
exec() does not flush the stdio buffers, so it is OK not to care about the stdio buffers if you (after calling
exec() and (if that fails) call
BTW: To understand that wrong buffering may cause, here is a former bug in Linux that has been recently fixed:
The standard requires
stderr to be unbuffered by default, but Linux ignored this and made
stderr line buffered and (even worse) fully buffered in case that stderr was redirected through a pipe. So programs written for UNIX did output stuff without newline too late on Linux.
See comment below, it seems to be fixed now.
This is what I do in order to work around this Linux problem:
* Linux comes with a broken libc that makes "stderr" buffered even
* though POSIX requires "stderr" to be never "fully buffered".
* As a result, we would get garbled output once our fork()d child
* calls exit(). We work around the Linux bug by calling fflush()
* before fork()ing.
This code does not harm on other platforms since calling
fflush() on a stream that was just flushed is a noop.