考虑以下代码:
#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] 删除。
我来说两句