sherrellbc
sherrellbc

Reputation: 4853

stderr and stdout - not buffered vs. buffered?

I was writing a small program that had various console output strings depending upon different events. As I was looking up the best way to send these messages I came across something that was a bit confusing.

I have read that stderr is used to shoot messages directly to the console - not buffered. While, in contrast, I read that stdout is buffered and is typically used to redirect messages to various streams?, that may or may not be error messages, to an output file or some other medium.

What is the difference when something is said to be buffered and not buffered? It made sense when I was reading that the message is shot directly to the output and is not buffered .. but at the same time I realized that I was not entirely sure what it meant to be buffered.

Upvotes: 3

Views: 7714

Answers (4)

ensc
ensc

Reputation: 6984

Assume

int main(void)
{
    printf("foo\n");
    sleep(10);
    printf("bar\n");
}

when executing it on the console

$ ./a.out

you will see foo line and 10 seconds later bar line (--> line buffered). When redirecting the output into a file or a pipe

$ ./a.out > /tmp/file

the file stays empty (--> buffered) until the program terminates (--> implicit fflush() at exit).

When lines above do not contain a \n, you won't see anything on the console either until program terminates.

Internally, printf() adds a character to a buffer. To make things more easy, let me describe fputs(char const *s, FILE *f) instead of. FILE might be defined as

struct FILE {
    int fd;   /* is 0 for stdin, 1 for stdout, 2 for stderr (usually) */
    enum buffer_mode mode;
    char buf[4096];
    size_t count; /* number of chars in buf[] */
};
typedef struct FILE *FILE;

int fflush(FILE *f)
{
    write(f->fd, f->buf, f->count);
    f->count = 0;
}

int fputc(int c, FILE *f)
{
    if (f->count >= ARRAY_SIZE(f->buf))
        fflush(f);
    f->buf[f->count++] = c;
} 

int fputs(char const *s, FILE *f)
{
    while (*s) {
        char c = *s++;

        fputc(c, f);

        if (f->mode == LINE_BUFFERED && c == '\n')
            fflush(f);
    }

    if (f->mode == UNBUFFERED)
        fflush(f);
}

Upvotes: 1

Max
Max

Reputation: 22325

When an output stream is buffered, it means that the stream doesn't necessarily output data the moment you tell it to. There can be significant overhead per IO operation, so lots and lots of little IO operations can create a bottleneck. By buffering IO operations and then flushing many at once, this overhead is reduced.

While stdout and stderr may behave differently regarding buffering, that is generally not the deciding factor between them and shouldn't be relied on. If you absolutely need the output immediately, always manually flush the stream.

Upvotes: 2

Scott Mermelstein
Scott Mermelstein

Reputation: 15397

A buffered stream is one in which you keep writing until a certain threshold. This threshold could be a specific character, as Konrad mentions for line buffering, or another threshold, such as a specific count of characters written.

Buffering is intended to speed up input/output operations. One of the slowest things a computer does is write to a stream (whether a console or a file). When things don't need to be immediately seen, it saves time to store it up for a while.

You are right, stderr is typically an unbuffered stream while stdout typically is buffered. So there can be times when you output things to stdout then output to stderr and stderr appears first on the console. If you want to make stdout behave similarly, you would have to flush it after every write.

Upvotes: 2

Konrad Lindenbach
Konrad Lindenbach

Reputation: 4961

Typically, stdout is line buffered, meaning that characters sent to stdout "stack up" until a newline character arrives, at which point that are all outputted.

Upvotes: 4

Related Questions