所以我一直在研究 libc 的 stdio 部分是如何实现的,我遇到了另一个问题。看着man setvbuf
我看到以下内容:
当文件上发生第一次 I/O 操作时,会调用 malloc(3),并获得一个缓冲区。
malloc
这是有道理的,除非您实际使用它,否则您的程序不应包含I/O。我对此的直觉反应是 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)
释放它或使用一些人提到的静态缓冲区。我问是因为这看起来确实是一个尴尬的设计决定。