Whats wrong with this print order

2019-05-31 20:02发布

问题:

have a look at this code:

 #include<stdio.h>
 #include <unistd.h>
    int main()
    {
            int pipefd[2],n;
            char buf[100];
            if(pipe(pipefd)<0)
                    printf("Pipe error");
            printf("\nRead fd:%d write fd:%d\n",pipefd[0],pipefd[1]);
            if(write(pipefd[1],"Hello Dude!\n",12)!=12)
                    printf("Write error");
            if((n=read(pipefd[0],buf,sizeof(buf)))<=0)
                    printf("Read error");
            write(1,buf,n);
            return 0;
    }

I expect the printf to print Read fd and write fd before Hello Dude is read from the pipe. But thats not the case... see here. When i tried the same program in our college computer lab my output was

Read fd:3 write fd:4
Hello Dude!

also few of our friends observed that, changing the printf statement to contain more number of \n characters changed the output order... for example..printf("\nRead fd:%d\n write fd:%d\n",pipefd[0],pipefd[1]); meant that Read fd is printed then the message Hello Dude! then the write fd is printed. What is this behaviour?? Note: Out lab uses a linux server on which we run terminals, i don't remember the compiler version though.

回答1:

It's because printf to the standard output stream is buffered but write to the standard output file descriptor is not.

That means the behaviour can change based on what sort of buffering you have. In C, standard output is line buffered if it can be determined to be connected to an interactive device. Otherwise it's fully buffered (see here for a treatise on why this is so).

Line buffered means it will flush to the file descriptor when it sees a newline. Fully buffered means it will only flush when the buffer fills (for example, 4K worth of data), or when the stream is closed (or when you fflush).

When you run it interactively, the flush happens before the write because printf encounters the \n and flushes automatically.

However, when you run it otherwise (such as by redirecting output to a file or in an online compiler/executor where it would probably do the very same thing to capture data for presentation), the flush happens after the write (because printf is not flushing after every line).

In fact, you don't need all that pipe stuff in there to see this in action, as per the following program:

    #include <stdio.h>
    #include <unistd.h>
    int main (void) {
        printf ("Hello\n");
        write (1, "Goodbye\n", 8);
        return 0;
    }

When I execute myprog ; echo === ; myprog >myprog.out ; cat myprog.out, I get:

Hello
Goodbye
===
Goodbye
Hello

and you can see the difference that the different types of buffering makes.

If you want line buffering regardless of redirection, you can try:

setvbuf (stdin, NULL, _IOLBF, BUFSIZ);

early on in your program - it's implementation defined whether an implementation supports this so it may have no effect but I've not seen many where it doesn't work.



回答2:

You shouldn't mix calls to write and printf on single file descriptor. Change write to fwrite.

Functions which use FILE are buffered. Functions which use file descriptors are not. This is why you may get mixed order.

You can also try calling fflush before write.



回答3:

When you write onto the same file, or pipe, or whatever by two means at once (direct IO and output stream) you can get this behaviour. The reason is that the output stream is buffered.

With fflush() you can control that behaviour.



回答4:

What is happening is that printf writes to stdout in a buffered way -- the string is kept in a buffer before being output -- while the 'write' later on writes to stdout unbuffered. This can have the effect that the output from 'write' appears first if the buffer from the printf is only flushed later on.

You can explicitly flush using fflush() -- but even better would be not to mix buffered and non-buffered writes to the same output. Type man printf, man fflush, man fwrite etc. on your terminal to learn more about what these commands do exactly.



标签: c pipe