即使在缓冲区完全填满之前,C 中已满缓冲的输出流是否可以自动刷新?

标签 c buffer

考虑这个代码:

#include <stdio.h>
int main()
{
    char buffer[500];
    int n = setvbuf(stdout, buffer, _IOFBF, 100);
    
    printf("Hello");
    while(1 == 1)
        ;
    return 0;
}
在 Linux 上运行时,“Hello”消息立即出现在输出设备上,然后程序无限期挂起。不应该在 stdout 之前缓冲输出是手动还是在正常程序终止时刷新或关闭?这似乎在 Windows 10 上发生,如果缓冲区大小指定为 130 字节或更多,Linux 上也会发生这种情况。我在两个系统上都使用 VS Code。
我错过了什么?我对完整缓冲概念有什么误解吗?

最佳答案

What am I missing? Am I wrong about the Full Buffering Concept?


你对这个概念没有错。正如@WilliamPursell 在 his answer 中所观察到的,规范语言的措辞存在回旋余地。 ,但是根据规范的明确意图,您的程序观察到的行为并未表现出完全缓冲。此外,我将规范解释为尽管出于某种原因无法实现意图,但仍然为实现留有空间,而不是为实现意图提供免费通行证,尽管可以合理地实现意图,但可以随意做一些不同的事情。
我在您的程序上针对 Linux 上的 Glibc 2.22 测试了此变体:
#include <stdio.h>

int main() {
    static char buffer[BUFSIZ] = { 0 };
    int n = setvbuf(stdout, buffer, _IOFBF, 100);

    if (n != 0) {
        perror("setvbuf");
        return 1;
    }

    printf("Hello");
    puts(buffer);
    return 0;
}
程序以状态 0 退出并且没有打印任何错误输出,因此我得出结论 setvbuf返回0,表示成功。但是,程序只打印了一次“Hello”,表明实际上它没有使用指定的缓冲区。如果我将指定的缓冲区大小增加到 setvbuf到 128 字节 (== 27) 那么输出是“HelloHello”,表明使用了指定的缓冲区。
那么,观察到的行为似乎是 setvbuf 的这个实现当提供的缓冲区指定为小于 128 字节时,静默将流设置为无缓冲。这也与您的程序版本的行为一致,但与我对函数规范的阅读不一致:

[...]The argument mode determines how stream will be buffered, as follows: _IOFBF causes input/output to be fully buffered [...]. If buf is not a null pointer, the array it points to may be used instead of a buffer allocated by the setvbuf function and the argument size specifies the size of the array; otherwise, size may determine the size of a buffer allocated by the setvbuf function. The contents of the array at any time are indeterminate.

The setvbuf function returns zero on success, or nonzero if an invalid value is given for mode or if the request cannot be honored.


( C17 , 7.21.5.6/2-3)
当我阅读规范时,setvbuf是否自由使用指定的缓冲区,由其自行决定,如果它选择不这样做,那么它可能会或可能不会使用指定大小的缓冲区,但它必须要么设置指定的缓冲模式,要么失败。将缓冲模式改为既不同于原始模式又不同于请求模式的方式与那些规范不一致,设置请求模式失败却返回0也是不一致的。
因为我得出的结论是这个 Glibc 版本的 setvbuf行为与语言规范相反,我想说你已经被 glibc 错误绊倒了。

1 但需要注意的是,规范中说缓冲区的内容在任何时候都是不确定的。因此,通过询问 setvbuf 后访问缓冲区要将其分配为流缓冲区,该程序会调用未定义的行为,因此,从技术上讲,它不能证明任何事情。

关于即使在缓冲区完全填满之前,C 中已满缓冲的输出流是否可以自动刷新?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66196393/

相关文章:

python - NumPy 是否有相当于 Matlab 缓冲区的功能?

c - realloc 失败的可能性有多大?

java - Java中的非阻塞缓冲区

node.js - 你如何解码 Node 中的连续比特流?

c - Xcode 给出了简单 C 数组的错误总和

java - FileOutputStream max_allowed_dequeued_buffers 3

C缓冲区溢出攻击

c - 如何从VC8中的2个静态库中获取所有符号冲突

c - C语言中一个宏给出了错误的值

c - 输入后下降