我一直在研究libc的stdio部分是如何实现的,然后我遇到了另一个问题。看着man setvbuf
,我看到了以下内容:
当文件上发生第一次I/O操作时,会调用malloc(3)并获取缓冲区。
这很有意义,除非你真正使用它,否则你的程序不应该在I/O中使用malloc
。我的第一反应是libc会自己清理这个混乱。我只能假设它确实这样做,因为valgrind没有报告任何内存泄漏(当然,他们可能会做一些肮脏的事情,并不直接通过malloc
分配它...但我们现在假设它确实使用malloc
)。
但是,你也可以指定自己的缓冲区...
int main() {
char *p = malloc(100);
setvbuf(stdio, p, _IOFBF, 100);
puts("hello world");
}
哦,不好了,内存泄漏! valgrind确认了这一点。因此,每当stdio自己分配缓冲区时,它就会被自动删除(最迟在程序退出时,但可能在流关闭时)。但是,如果您明确指定缓冲区,则必须自行清理。
然而,有一个问题。手册还说:
您必须确保buf指向的空间仍然存在于流关闭时,这也发生在程序终止时。例如,以下内容无效:
现在对于标准流来说变得更加有趣了。如果要正确清除为其手动分配的缓冲区,该怎么办,因为它们在程序终止时关闭?我可以想象在文件结构中有一个“在我关闭时清理这个”的标志,但这会变得麻烦,因为如果我正确地阅读了这个标志,做类似这样的事情:
setvbuf(stdout, 0, _IOFBF, 0);
printf("hello ");
setvbuf(stdout, 0, _IOLBF, 0);
printf("world\n");
这句话会导致标准库进行2次分配:
编辑: 对我的问题补充说明。既然我必须如果参数buf为NULL,则仅影响模式;新缓冲区将在下一次读取或写入操作时分配。
free
任何我传递给setvbuf
的缓冲区,如果我确实在stdout
上使用它,有没有实际的方法可以free
它?它必须存活到程序结束。我能想到的最好的办法是fclose(stdout)
然后释放它或者像一些人提到的那样使用静态缓冲区。我问这个问题是因为它似乎是一个笨拙的设计决策。