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 stdout
buffer.
Now, these fork()
calls in your example create 8 processes in total - all of them with a copy of the state of the stdout
buffer.
By definition, all these processes call exit()
when returning from main()
and exit()
calls 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 fork()
) call exec()
and (if that fails) call _exit()
.
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.
*/
fflush(stderr);
This code does not harm on other platforms since calling fflush()
on a stream that was just flushed is a noop.
./prog1 > prog1.out
) or a pipe (./prog1 | cat
). Prepare to have your mind blown. :-) fork()
is somewhat unix-specific too, so it would seem that this is quite on-topic for unix.SE.