我正在编写一个小程序,该程序根据不同的事件具有各种控制台输出字符串。当我查找发送这些消息的最佳方式时,我遇到了一些有点令人困惑的事情。
我已经读到stderr
用于将消息直接发送到控制台 - not buffered
.相比之下,我读到stdout
是buffered
的,通常用于将消息重定向到各种streams?
,这可能是也可能不是错误消息,输出文件或其他介质。
当某物被称为缓冲和不缓冲时,有什么区别?当我阅读消息直接拍摄到输出并且没有缓冲时,这是有道理的。但与此同时,我意识到我不完全确定缓冲意味着什么。
通常,stdout 是行缓冲的,这意味着发送到 stdout 的字符"堆叠",直到换行符到达,此时全部输出。
流是你一直写入到某个阈值的流。 此阈值可以是特定字符,如 Konrad 提到的行缓冲,也可以是另一个阈值,例如写入的特定字符数。
缓冲旨在加快输入/输出操作的速度。 计算机执行的最慢的操作之一是写入流(无论是控制台还是文件)。 当东西不需要立即看到时,可以节省时间将其存放一段时间。
你是对的,stderr
通常是未缓冲的流,而stdout
通常是缓冲的。 因此,有时您可以将内容输出到 stdou
t,然后输出到 stderr
,stderr
首先出现在控制台上。 如果你想让stdout
的行为相似,你必须在每次写入后flush
它。
当输出流被缓冲时,这意味着该流不一定在您告诉它时输出数据。每个 IO 操作可能会产生大量开销,因此大量小 IO 操作可能会造成瓶颈。通过缓冲 IO 操作,然后一次刷新多个操作,可以减少此开销。
虽然stdout
和stderr
在缓冲方面的行为可能不同,但这通常不是它们之间的决定因素,不应依赖。如果您绝对需要立即输出,请始终手动flush
流。
假设
int main(void)
{
printf("foon");
sleep(10);
printf("barn");
}
在控制台上执行时
$ ./a.out
您将看到foo
行,10 秒后bar
行(-->行已缓冲)。 将输出重定向到文件或管道时
$ ./a.out > /tmp/file
该文件保持为空(-->缓冲),直到程序终止(--> 退出时隐式 fflush() )。
当上面的行不包含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);
}