请观察以下终端输出:
$ cat fprintf-closed-file.c
#include <stdio.h>
int main()
{
FILE * ofile = fopen("/tmp/goo", "w");
int success = fprintf(ofile, "Hello %sn", "World!");
printf("Success: %dn", success);
fclose(ofile);
success = fprintf(ofile, "Trying again...");
printf("Success: %dn", success);
}
$ clang -o fprintf-closed-file fprintf-closed-file.c
$ ./fprintf-closed-file
Success: 13
Success: 15
$ cat /tmp/goo
Hello World!
C11标准第7.21.6.1节说:
fprintf 函数将输出写入流指向的流, 受指定如何 后续参数将转换为输出。
后跟转换说明符的说明,但结尾为:
返回
fprintf 函数返回字符数 传输,如果输出或编码错误,则为负值 发生。
看起来,鉴于文件在第二次fprintf
调用时已关闭,它应该会失败,但事实并非如此。我在 Kubuntu Trusty 64 位上使用 Clang 4.0.1 和 GCC 4.8.4 对此进行了测试。
我对标准的理解有问题,还是我应该提交错误?
引用C99,7.19.3文件:
- [...]在关闭关联的文件(包括标准文本流)后,指向
FILE
对象的指针的值不确定。
因此:
fclose(ofile);
success = fprintf(ofile, "Trying again...");
第二行从ofile
读取,它(在fclose
之后)有一个不确定的值。这具有未定义的行为。
另见附件J.2:
在以下情况下未定义该行为: [...]
具有自动存储持续时间的对象的值在不确定时使用(6.2.4、6.7.8、6.8)。
指向 FILE 对象的指针的值在关闭关联文件 (7.19.3) 后使用。
不,这不是错误。您正在做的是未定义的行为,如C11 Annex J.2
:
在以下情况下未定义该行为:
。
- 指向
FILE
对象的指针的值在关联文件关闭后使用 (7.21.3)
因此,在这种情况下,实现可以自由地做任何它想做的事情。根据引文,第7.21.3
节提供了有关此事的更多详细信息。