众所周知,STDOUT 在 Linux 中是缓冲的。我的问题是:1)它是所有进程共享的全局缓冲区吗?还是每个进程一个缓冲区?2)缓冲区在哪里?在堆栈、堆或静态区域?3) 谁创造了它?
3 回答
stdout
是标准库创建的 CFILE
指针,因此相关代码作为 C 库的一部分加载。在 Linux 上,它将根据 Posix 文件描述符来实现。
您的 C 库和内核都可能使用缓冲;您必须检查各个文件。我建议先看C库源代码的相关部分(即实现的部分<stdio.h>
),应该很有教育意义。
详细了解 C 标准库的最佳资源是 PJ Plauger 的标准 C 库。他描述了他自己实现库时出现的所有问题(在 MSWord 中!在 win3.1 笔记本电脑上!在度假!)。
他还提供了有关如何使用(和测试)每个功能的详细信息。
对于 Unix (Linux) 端,您应该开始阅读“inode”,这是用于存储内存中缓存文件的经典数据结构。这方面的经典著作是Maurice J. Bach的 The Design of the UNIX Operating System。
好吧,既然您因为没有阅读所有旧书和每个相关的 wiki 页面而受到适当的责骂。
这是来自The Standard C Library的相关引述,p。256.
原则上,您可以对 I/O 功能如何为流缓冲数据进行一定程度的控制。但是,您必须意识到,缓冲是基于关于 I/O 模式的各种猜想的优化。这些猜想通常是正确的,许多实现都遵循您的建议。但他们不必这样做。实现可以自由地忽略大多数缓冲请求。
不过,如果您认为较大的缓冲区会提高性能或较小的缓冲区会节省空间,您可以提供自己的候选缓冲区。在打开文件之后调用该函数
setvbuf
,在对流执行任何其他操作之前。(避免使用不太灵活的旧函数setbuf
。)您可以指定 I/O 是否应完全缓冲、按文本行缓冲或不缓冲。它可能会对您的程序的执行情况产生影响。...
setbuf
--setvbuf
代替这个函数来获得更多的控制权。
setvbuf
-- 通常,最好让标准 C 库决定如何为您缓冲输入/输出。如果您确定不需要缓冲或一次缓冲,请使用此函数正确初始化流。打开流后setvbuf
立即调用。几乎任何对流的操作都会抢占您选择缓冲策略的权利。如果您使用此调用指定自己的缓冲区,请不要假设流将实际使用它。并且永远不要在流打开时更改缓冲区的内容。模式(第三个)参数必须具有上述值、_IOFBF
或_IOLBF
之一_IONBF
。另请参阅 [其他地方] 描述的宏BUFSIZ
。...
/* setbuf function */
#include "xstdio.h"
int (setbuf)(FILE *str, char *buf)
{ /* set up buffer for a stream */
setvbuf(str, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
}
/* setvbuf function */
#include <limits.h>
#include <stdlib.h>
#include "xstdio.h"
int (setvbuf)(FILE *str, char *abuf, int smode, size_t size)
{ /* set up buffer for a stream */
int mode;
unsigned char *buf = (unsigned char *)abuf;
if (str->_Mode & (_MREAD|_MWRITE))
return (-1);
mode = smode == _IOFBF ? 0
: smode == _IOLBF ? _MLBF
: smode == _IONBF ? _MNBF : -1;
if (mode == -1)
return (-1);
if (size == 0)
buf = &str->_Cbuf, size = 1;
else if (INT_MAX < size)
size = INT_MAX;
if (buf)
;
else if ((buf = malloc(size)) == NULL)
return (-1);
else
mode |= _MALBUF;
if (str->_Mode & _MALBUF)
free(str->_Buf), str->_Mode &= ~_MALBUF;
str->_Mode |= mode;
str->_Buf = buf;
str->_Bend = buf + size;
str->_Next = buf;
str->_Rend = buf;
str->_Wend = buf;
return (0);
}
因此,至少在这个实现中,默认缓冲区可能存在于 FILE 结构中并在堆上分配。我们可以在这里看到它的兄弟,一个字符缓冲区 ( str->_CBuf
),用于“无缓冲”。