2

我正在编写一个小程序,该程序根据不同的事件具有各种控制台输出字符串。当我在寻找发送这些消息的最佳方式时,我遇到了一些令人困惑的事情。

我已经阅读了stderr用于将消息直接发送到控制台的内容 - not buffered. 相比之下,我读到的那stdoutbuffered并且通常用于将消息重定向到各种streams?可能是或可能不是错误消息的输出文件或其他介质。

当某些东西被称为缓冲和不缓冲时有什么区别?当我读到消息直接发送到输出并且没有缓冲时,这是有道理的。但同时我意识到我并不完全确定缓冲的含义。

4

4 回答 4

3

通常,stdout 是行缓冲的,这意味着发送到 stdout 的字符“堆叠”直到换行符到达,此时所有字符都被输出。

于 2013-11-14T23:31:03.843 回答
2

当输出流被缓冲时,这意味着流不一定会在您告诉它的那一刻输出数据。每个 IO 操作可能会有很大的开销,因此大量的小 IO 操作会造成瓶颈。通过缓冲 IO 操作,然后一次刷新许多操作,可以减少这种开销。

虽然stdout并且stderr可能在缓冲方面表现不同,但这通常不是它们之间的决定因素,不应依赖。如果您绝对需要立即输出,请始终手动flush输入流。

于 2013-11-14T23:38:03.993 回答
2

缓冲流是您一直写入到某个阈值的流。该阈值可以是特定字符,如 Konrad 提到的行缓冲,也可以是另一个阈值,例如写入的特定字符数。

缓冲旨在加速输入/输出操作。计算机做的最慢的事情之一就是写入流(无论是控制台还是文件)。当不需要立即查看事物时,可以节省时间将其存储一段时间。

你是对的,stderr通常是一个无缓冲的流,而stdout通常是缓冲的。因此,有时您将内容输出到stdout 然后输出到stderrstderr首先出现在控制台上。如果您想做出stdout类似的行为,flush则必须在每次写入后都这样做。

于 2013-11-14T23:34:30.763 回答
1

认为

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

在控制台上执行时

$ ./a.out

您将看到fooline 和 10 秒后的barline(--> line buffered)。将输出重定向到文件或管道时

$ ./a.out > /tmp/file

文件保持为空(--> 缓冲)直到程序终止(--> 退出时隐式 fflush())。

当上面的行不包含 a\n时,在程序终止之前,您也不会在控制台上看到任何内容。

在内部,printf()将一个字符添加到缓冲区。为了使事情更容易,让我来描述fputs(char const *s, FILE *f)而不是。 FILE可以定义为

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);
}
于 2013-11-14T23:34:54.350 回答