即使缓冲区已满,也可以自动刷新C中已完全缓冲的输出流吗?

Shah Fahad |

考虑以下代码:

#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手动或在正常程序终止时刷新或关闭输出之前对输出进行缓冲吗?如果缓冲区大小指定为130字节或更大,那似乎就是在Windows 10上发生的事情,也是在Linux上发生的事情。我在两个系统上都使用VS Code。

我想念什么?我对完全缓冲概念有误吗?

约翰·布林格

我想念什么?我对完全缓冲概念有误吗?

您对这个概念没有错。正如@WilliamPursell在他的回答中观察到的那样,规范语言的措辞中有摆动的余地,但是根据规范的明确意图,您的程序观察到的行为不会表现出完全的缓冲。而且,我将规范解释为尽管有一个或多个原因无法实现意图,但仍为实现的一致性留有余地,而不是为合理地可以实现意图而随意做一些事情的实现提供免费通行证。

我在Linux上针对Glibc 2.22在您的程序上测试了此变体:

#include <stdio.h>

int main() {
    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个字节(== 2 7),则输出为“ HelloHello”,表明已使用指定的缓冲区。

因此,观察到的行为似乎是1,即当提供的缓冲区被指定为小于128字节时,此实现将setvbuf静默方式将流设置为缓冲。这也与您的程序版本的行为一致,但是与我对函数规范的阅读不一致:

[...]该参数mode确定stream如何缓冲,如下所示:_IOFBF使输入/输出被完全缓冲[...]。如果buf不是null指针,则可以使用它指向的数组来代替setvbuf函数分配的缓冲区,并且参数size指定数组的大小;否则,size可以确定该setvbuf函数分配的缓冲区的大小数组的内容在任何时候都是不确定的。

setvbuf如果成功,函数将返回零;如果给出了无效值,mode或者无法满足请求,则函数将返回非零

C17,7.21.5.6/2-3)

当我阅读该规范时,setvbuf可以自由决定是否使用指定的缓冲区,如果选择不使用,则可以使用也可以不使用指定大小的缓冲区,但是必须设置指定的缓冲区模式或失败。将缓冲模式更改为不同于原始模式和请求模式的缓冲与这些规范不一致,并且未能设置请求模式并返回0也是不一致的。

由于我得出的结论是该Glibc版本setvbuf与语言规范背道而驰,因此我想说您已经遇到了glibc错误。


1但应注意的是,规范指出缓冲区的内容在任何时候都是不确定的。因此,通过在要求setvbuf将其分配为流缓冲区之后访问该缓冲区,此程序将调用未定义的行为,因此,从技术上讲,它什么都没有证明。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

输出缓冲区是否自动刷新?

来自分类Dev

输出缓冲区是否自动刷新?

来自分类Dev

C ++刷新缓冲区

来自分类Dev

在Apache / Nginx设置中刷新输出缓冲区

来自分类Dev

如何在到达缓冲区而不是缓冲区已满时读取缓冲区中的数据?

来自分类Dev

如何在流缓冲区C中添加参数

来自分类Dev

流缓冲区中的默认内容

来自分类Dev

在 emscripten 中处理输出缓冲区

来自分类Dev

缓冲区何时刷新

来自分类Dev

是否可以在C ++中以零拷贝拼接缓冲区?

来自分类Dev

进程退出时,缓冲区会自动刷新到磁盘吗?

来自分类Dev

即使在Xlib中刷新了缓冲区,也没有显示该行

来自分类Dev

每N个字符刷新输出缓冲区

来自分类Dev

PHP输出缓冲区刷新,然后清除

来自分类Dev

如何正确刷新 PHP 输出缓冲区?

来自分类Dev

在正在运行的程序中强制输出缓冲区刷新

来自分类Dev

缓冲区通常比流处理更快吗?

来自分类Dev

是否可以将流同步转换为缓冲区?

来自分类Dev

C ++中的缓冲区大小

来自分类Dev

C ++中的位缓冲区

来自分类Dev

在C ++中解析协议缓冲区

来自分类Dev

C中的缓冲区溢出与获取

来自分类Dev

在C#中同步缓冲区

来自分类Dev

C中自发的缓冲区溢出

来自分类Dev

BufferedWriter / PrintWriter / OutputStreamWriter不会刷新缓冲区,直到调用.close()为止(通过套接字输出流)

来自分类Dev

未能刷新缓冲区。没有缓冲区可以用 ob_end_flush() 方法刷新

来自分类Dev

我应该在 Akka 流中的 Kafka 源之后添加缓冲区吗

来自分类Dev

PHP:是否可以获取非阻塞输出缓冲区?

来自分类Dev

在Node.JS中刷新缓冲区数据