1

I have a C programme like this:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
    printf("hello world (pid:%d)\n", (int)getpid());
    int rc = fork();
    if (rc < 0)
    { // fork failed; exit
        fprintf(stderr, "fork failed\n");
        exit(1);
    }
    else if (rc == 0)
    { // child (new process)
        printf("hello, I am child (pid:%d)\n", (int)getpid());
    }
    else
    { // parent goes down this path (main)
        printf("hello, I am parent of %d (pid:%d)\n",
               rc, (int)getpid());
    }
    return 0;
}

After finishing the gcc compilation, I got the "a.out" executable file. And I got the correct programme output in the Linux shell.

hello world (pid:1056088)
hello, I am parent of 1056089 (pid:1056088)
hello, I am child (pid:1056089)

But if I use the watch command to execute it, I got the output like this:

hello world (pid:1056155)
hello, I am parent of 1056156 (pid:1056155)
hello world (pid:1056155)
hello, I am child (pid:1056156)

I don't know why if I use the watch command, there would be an extra line in the output.

I have tried to delete the line "printf("hello world (pid:%d)\n", (int)getpid());", there would be no difference between the outputs. And if I add the "fflush(stdout);" line under it, it also has no difference between the outputs.

Now I know that "stdout" is line buffered. But I wonder why the "watch" commmand has the diffwerent output with the "./a.out" format. Is this a bug, or a feature?

I would be appreciate if anybody can explain it to me.

Mario
  • 11
  • 2

1 Answers1

1

When printing to a pipe, standard output is buffered. When you fork, the whole program is copied to the fork, including the contents of the buffer.

If you print more than just one line, you can see that only the final part of it gets copied and printed twice, e.g.

for (int i = 1; i < 64000; ++i) printf("%d\n", i);

On my machine, everyting up to 63970 gets printed once, the rest is printed twice:

a.out | grep 6397[01]
63970
63971
63971

See also Why does printf not flush after the call unless a newline is in the format string?

choroba
  • 231,213
  • 25
  • 204
  • 289
  • Thank you. Now I know that stdout is line buffered. But I also have a question. Why there would be an extra output line if I use the "watch" command to execute it, while if I execute it in the "./a.out" format, there would be no extra line. – Mario Jan 27 '23 at 09:20
  • Stdout is line buffered when outputting to a terminal, but it's fully buffered when redirected to a pipe. The existence of the extra line(s) is because the fork copies the buffer, as already noted in the answer. – choroba Jan 27 '23 at 09:33