1

I encountered this in my school work and it didn't produce what I thought it should:

int main() {
    printf("c");
    fork();
    printf("d");
}

I know there are several things that aren't good about this code (i.e. no parameters in main, no variable for the return value from fork, no return statement at the end, etc.), but this is how it was presented and it's not relevant to my question anyway.

This code produces the output:

cdcd

It was my understanding that when fork is called, both parent and child would resume/begin on the line after the fork call. Based on that, I would have expected the output to be:

cdd

Assuming, of course, that the fork call is successful. Can anyone explain to me why that "c" is printed a second time even though it's on the line before the fork call?

Thanks! M_MN

M_MN
  • 51
  • 4
  • Thanks for the answers everyone. I think you all could count as the "answer." It's too bad I can only pick one (I assume. I haven't done it yet and this is my first question on this site.) I think I get it now. I had either forgotten, or never knew, that C doesn't print to the terminal in a case like this until the program ends. That seemed to be key to understanding. So both parent and child had a "C" in their buffer after the fork, then both added a "d" to their buffer, and then the output at the end is from them both printing to terminal after the program ended. Sound right? – M_MN Oct 08 '21 at 02:23
  • 1
    It's not true that C doesn't print to the screen until the program ends. The issue is that `printf` doesn't print to the screen until its buffer is flushed. The flushing of the buffer can happen for several reasons: The buffer fills up, a new line is printed, `fflush` is explicitly called, **or** the program exits. – Daniel Walker Oct 08 '21 at 02:24
  • Ah, good to know. Well, in the case of this program, it probably waited until program exit since those other scenarios didn't happen. Thanks! – M_MN Oct 08 '21 at 02:26

3 Answers3

5

You forked your program before flushing stdout (i.e.: data was still in the output buffer). Just call fflush(stdout) to fix it:

❯ cat test.c
#include <stdio.h>
#include <unistd.h>

int main() {
    printf("c");
    fflush(stdout);
    fork();
    printf("d");
}

[22:14:01]~/devel
❯ clang test.c -o test
[22:14:07]~/devel
❯ ./test
cdd[22:14:09]~/devel
ichramm
  • 6,437
  • 19
  • 30
4

The reason you're seeing c twice is that the fork() duplicates the unprinted buffered output. You could flush the output stream before the fork():

fflush(stdout);

Or you could set stdout to be unbuffered, but you should do this first, before calling printf() the first time:

setvbuf(stdout, NULL, _IONBF, 0);
sj95126
  • 6,520
  • 2
  • 15
  • 34
3

Here's what I'm guessing is happening. printf writes to the stream stdout. Since you didn't flush stdout after printing "c" nor did that string end in a new line, the character sat there in a user-space buffer. When you called fork, the child process got a copy of the parent's virtual address space including the buffered text. When both programs exited, their buffers were flushed and so "c" showed up twice.

Try adding fflush(stdout); just prior to the call to fork.

Daniel Walker
  • 6,380
  • 5
  • 22
  • 45