考虑以下 C 语言代码,尽管非常困惑:
#include<stdio.h>
int main() {
char buf[3]; //a new, small buffer
FILE *fp = fopen("test.txt", "r"); //our test file, with the contents "123abc"
setvbuf(fp, buf, _IOFBF, 2); //we assign our small buffer as fp's buffer \
//in fully buffered mode
char character = fgetc(fp); // get the first character...
character = fgetc(fp); // and the next...
character = fgetc(fp); // and the next... (third character, '3')
buf[2] = '\0'; //add a terminating line for display
fputs(buf, stderr); //write our buffer to stderr, should show up immediately
}
编译并运行代码将打印“3a”作为我们自行指定的缓冲区 buf 的内容。我的问题是:这个缓冲区是如何填满的?调用 fgetc() 是否意味着多次调用直到缓冲区已满然后停止(我们只调用了三个 fgetc,这不应该包括现在'a')?第一个缓冲区是“12”,这是否意味着当另一个 fgetc() 调用被调用并且指针引用缓冲区范围之外的内容时,缓冲区是被清除然后填充下一个数据 block ,还是被简单地覆盖?我知道缓冲区大小取决于平台,所以我更关心一般情况下,读取模式下的 fopen()ed 流如何将字符拉入其缓冲区。
最佳答案
缓冲区,以及填充的具体方式和时间,是 stdio 包中的一个实现细节。但它可能的实现方式是fgetc 从缓冲区中获取一个字符,如果缓冲区中有字符可用的话。如果缓冲区为空,它会通过(在您的情况下)从文件中读取另外两个字符来填充缓冲区。
因此,您的第一个 fgetc 将从文件中读取 12 并将其放入缓冲区,然后返回 '1'。你的第二个 fgetc 不会从文件中读取,因为缓冲区中有一个字符可用,并返回 '2'。你的第三个fgetc会发现缓冲区是空的,所以它会从文件中读取3a放入缓冲区,然后返回'3'强>。因此,当您打印缓冲区的内容时,它将是3a。
请注意,这里有两个级别的“阅读”。首先,您有 fgetc 调用,然后,在该级别之下,stdio packade 中的代码正在从文件中读取。如果我们假设这是在 Unix 或 Linux 系统上,则第二种类型的读取是使用系统调用 read(2) 完成的。
较低级别的读取会立即填满整个缓冲区,因此您不需要像调用 fgetc 那样多次调用 read。 (这就是拥有缓冲区的全部意义所在。)
关于c - 只读模式下的 fopen() 及其缓冲区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23338218/