setvbuf() - buf 为 NULL 时的缓冲区大小
setvbuf() - buffer size when buf is NULL
我已经阅读了 similar question 的答案,但我对执行 I/O 文件时的流缓冲更感兴趣。
当我运行下面的代码
#include <stdio.h>
int main(void) {
printf("%d\n", BUFSIZ);
FILE *fp = fopen("ekomi.txt", "wb");
char array[2] = {'a', 'b'};
fwrite(array, sizeof(char), 2, fp);
fclose(fp);
return 0;
}
它打印 BUFSIZ = 8192。
据我所知,BUFSIZ 应该是 glibc 使用的值,用于在 fopen 之后默认创建的缓冲区大小(据我所知,这应该与调用 setvbuf 将 NULL 指针传递给参数 buf 相同)。
我运行这个带有massif的程序,输出清楚地表明glibc分配的缓冲区是4096字节长
massif output
GNU C 库文档本身并不清楚缓冲区的默认大小:
If you specify a null pointer as the buf argument, then setvbuf allocates a buffer itself using malloc. This buffer will be freed when you close the stream.
所以我的问题是,glibc 如何决定为缓冲区分配多少内存?
简短回答:BUFSIZ 是允许的最大缓冲区大小,但 malloc 中使用的缓冲区大小由文件系统块大小给出。
长答案:
让我们回顾一下当我们让一个 NULL 指针作为 buf 传递时 setvbuf 做了什么。
https://sourceware.org/git/?p=glibc.git;a=blob;f=libio/iosetvbuf.c#l60
_IO_DOALLOCATE (fp)
https://sourceware.org/git/?p=glibc.git;a=blob;f=libio/libioP.h#l237
#define _IO_DOALLOCATE(FP) JUMP0 (__doallocate, FP)
这里它使用 JUMP0 宏调用与 FILE vtable 关联的“__doallocate”函数,它最终调用 _IO_file_doallocate() 定义在这里:
https://sourceware.org/git/?p=glibc.git;a=blob;f=libio/filedoalloc.c#l97
#if _IO_HAVE_ST_BLKSIZE
if (st.st_blksize > 0 && st.st_blksize < _IO_BUFSIZ)
size = st.st_blksize;
#endif
在上述行中,您可以看到我在简短回答中提到的内容。它使用 stat64 结构 (https://linux.die.net/man/2/stat64) 检索文件系统的块大小,如果它小于 BUFSIZ,则相应地设置大小。
我已经阅读了 similar question 的答案,但我对执行 I/O 文件时的流缓冲更感兴趣。
当我运行下面的代码
#include <stdio.h>
int main(void) {
printf("%d\n", BUFSIZ);
FILE *fp = fopen("ekomi.txt", "wb");
char array[2] = {'a', 'b'};
fwrite(array, sizeof(char), 2, fp);
fclose(fp);
return 0;
}
它打印 BUFSIZ = 8192。 据我所知,BUFSIZ 应该是 glibc 使用的值,用于在 fopen 之后默认创建的缓冲区大小(据我所知,这应该与调用 setvbuf 将 NULL 指针传递给参数 buf 相同)。 我运行这个带有massif的程序,输出清楚地表明glibc分配的缓冲区是4096字节长
massif output
GNU C 库文档本身并不清楚缓冲区的默认大小:
If you specify a null pointer as the buf argument, then setvbuf allocates a buffer itself using malloc. This buffer will be freed when you close the stream.
所以我的问题是,glibc 如何决定为缓冲区分配多少内存?
简短回答:BUFSIZ 是允许的最大缓冲区大小,但 malloc 中使用的缓冲区大小由文件系统块大小给出。
长答案: 让我们回顾一下当我们让一个 NULL 指针作为 buf 传递时 setvbuf 做了什么。
https://sourceware.org/git/?p=glibc.git;a=blob;f=libio/iosetvbuf.c#l60
_IO_DOALLOCATE (fp)
https://sourceware.org/git/?p=glibc.git;a=blob;f=libio/libioP.h#l237
#define _IO_DOALLOCATE(FP) JUMP0 (__doallocate, FP)
这里它使用 JUMP0 宏调用与 FILE vtable 关联的“__doallocate”函数,它最终调用 _IO_file_doallocate() 定义在这里:
https://sourceware.org/git/?p=glibc.git;a=blob;f=libio/filedoalloc.c#l97
#if _IO_HAVE_ST_BLKSIZE
if (st.st_blksize > 0 && st.st_blksize < _IO_BUFSIZ)
size = st.st_blksize;
#endif
在上述行中,您可以看到我在简短回答中提到的内容。它使用 stat64 结构 (https://linux.die.net/man/2/stat64) 检索文件系统的块大小,如果它小于 BUFSIZ,则相应地设置大小。