使用glibc 2.24解决 - 请参阅下面的更新
这是一段C代码(用gcc 5.3.1编译,glibc 2.23):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
int main() {
const char* s1="Original content of file.\n"
"still original content and some remaining original content.\n";
const char* s2="overwriting data with new content\n";
const char* s3="appended data\n";
const size_t bufsz=strlen(s1)+1;
char buf[bufsz];
FILE *f;
int r;
f=fmemopen(buf,bufsz,"w");
assert(f!=NULL);
// setbuf(f, NULL); // variant no. 1
// setbuffer(f, buf, bufsz); // variant no. 2
r=fwrite(s1,strlen(s1),1,f);
assert(r==1);
r=fflush(f);
assert(r==0);
rewind(f);
r=fwrite(s2,strlen(s2),1,f);
assert(r==1);
r=fwrite(s3,strlen(s3),1,f);
assert(r==1);
r=fclose(f);
assert(r==0);
printf("%s",buf);
}
它做我期望的 - 输出是:
overwriting data with new content
appended data
and some remaining original content.
现在,manpage fmemopen(3)建议禁用缓冲(取消注释变体1),或者明确地将buf
设置为缓冲区(取消注释变体2)。
然而,在这两种情况下,我都得到了结果:
appended data
ta with new content
ginal content and some remaining original content.
因此,附加数据不是按照预期在第二个内容之后写入,而是覆盖了第二个内容。
如果我以二进制模式打开文件(即用&#34; w&#34;模式替换&#34; wb&#34;),行为将保持不变。
valgrind不会报告任何错误(除了误报&#34;源和目标重叠&#34;在缓冲的情况下。后者是由于尝试将STDIO缓冲区写入内存,这确实是同一个地址。)
有什么问题?我犯了错误吗?或者这是一个GLIBC错误?
8月4日,新的glibc 2.24版本发布。使用gcc 5.4.0和glibc 2.24,变体号。 1(无缓冲的文件)工作正常。变体2(自缓冲版本)给出了不同但仍然错误的结果。因此,我相信R ..是正确的,声称这是manpage fmemopen(3)中的文档错误。我会提出错误报告......
答案 0 :(得分:2)
现在,manpage fmemopen(3)建议禁用缓冲(取消注释变量1),或者明确地将buf设置为缓冲区(取消注释变体2)。
后者绝对是未定义的行为。不要这样做。我不清楚你在Linux手册页中找到了什么文本:
或者,调用者可以明确地将buf设置为stdio流 缓冲区,同时使用:
通知stdio缓冲区的大小setbuffer(stream, buf, size);
试图表达,但它是一个文档错误,应该可以删除。
对于无缓冲模式不起作用,这可能是一个glibc错误。尝试尽可能减少测试用例,针对最近的glibc进行测试,如果仍然发生,请提交glibc bugzilla的错误报告:
https://sourceware.org/bugzilla/enter_bug.cgi?product=glibc
当您想立即了解错误时,一个安全的选择就是调用fflush
并检查返回值。