提问人:Dalton Cézane 提问时间:5/11/2023 最后编辑:OkaDalton Cézane 更新时间:5/12/2023 访问量:96
使用 fclose 的奇怪行为
Strange behavior using fclose
问:
测试 fclose 函数时,未到达该行。如果删除该行,则显示该消息。printf("File \"file2.bin\" inexistent!");
fclose(p_file2)
#include <stdio.h>
int main()
{
printf("Hello files");
FILE *p_file1, *p_file2;
p_file1 = fopen("file1.bin", "w+b");
p_file2 = fopen("file2.bin", "r+b");
if (p_file2 == NULL)
printf("File \"file2.bin\" inexistent!");
fclose(p_file1);
fclose(p_file2);
return 0;
}
为什么会这样?
答:
4赞
William Pursell
5/11/2023
#1
这里有 2 个主要问题。首先是导致未定义的行为,所以对另一点的推测真的没有意义,但这显然是混乱的根源。 并不总是将任何数据写入输出流。相反,数据被缓冲,写入可能会推迟到以后对程序的调用或直到程序退出(或调用 or 或其他条件)。由于您的程序被调用,因此发生了不好的事情,并且本应延迟的写入从未发生,因此您看不到该消息。fclose(NULL)
printf
printf
fwrite
fflush
fclose(NULL)
尝试在 之后立即添加一个调用。fflush
printf
评论
2赞
G. Sliepen
5/11/2023
在格式字符串的末尾添加换行符 ('\n') 也会有所帮助,通常标准输出是行缓冲的。
3赞
John Bollinger
5/11/2023
fsync()
不是适合这项工作的工具,而且在这种情况下它不容易使用,因为它需要文件描述符,而不是流。也许你的意思是?fflush()
0赞
Andreas Wenzel
5/11/2023
您可能想澄清有必要编写 ,否则,OP 可能会尝试刷新其他流之一。fflush( stdout );
1赞
Konrad Rudolph
5/11/2023
@AndreasWenzel 是的,我的评论是 wong,实际上我什至找不到那是 UB。威廉,你能引用一个参考资料说这是UB吗?fclose(NULL)
1赞
Andreas Wenzel
5/11/2023
@KonradRudolph:我认为根据 ISO C11 标准 §7.1.4 ¶1 的一般规则,该行为是未定义的。
1赞
Jabberwocky
5/11/2023
#2
仅调用 实际返回的有效 FILE 指针。fclose
fopen
基本上你想要这个:
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("Hello files");
FILE* p_file1, * p_file2;
p_file1 = fopen("file1.bin", "w+b");
if (p_file1 == NULL)
{
printf("Can't open file.\n"); // add \n
exit(1);
}
p_file2 = fopen("file2.bin", "r+b");
if (p_file2 == NULL)
{
fclose(p_file1); // this can be ommited because files are closed automatically upon exit
printf("Can't open file.\n"); // add \n
exit(1);
}
// here we know for sure that both p_file1 and p_file1 are valid
fclose(p_file1);
fclose(p_file2);
return 0;
3赞
Harith
5/11/2023
#3
- 传递指针以调用未定义的行为。
NULL
fclose()
当程序在失败时退出时,我们可以有这样的函数:fopen()
static void open_sesame (const char *restrict stream, const char *restrict mode)
{
if (!fopen (stream, mode)) {
perror ("fopen():");
exit (EXIT_FAILURE);
}
}
现在,您的代码简化为:
FILE *fp1 = open_sesame ("file1.bin", "w+b");
FILE *fp2 = open_sesame ("file2.bin", "r+b");
...
fclose (fp1);
fclose (fp2);
- 缓冲的数据在调用时或程序终止时被刷新。如果是行缓冲的(通常在流连接到终端/控制台时出现这种情况),则当遇到换行符时,流也将被刷新。但是,由于程序调用了未定义的行为,因此无法对程序执行的继续做出假设。
printf()
fflush (stdout)
stdout
在调用 或调用 中添加换行符。printf()
fflush (stdout);
脚注:
该标准未定义行为,因此此规则适用:
除非明确说明,否则以下每一项声明均适用 否则在下面的详细说明中: 如果参数 函数具有无效值(例如,域外的值 函数,或程序地址空间外的指针, 或 null 指针,或指向不可修改存储的指针,当 相应的参数不是 const 限定的)或类型(在 promotion) 不是由具有可变数 参数,则行为未定义。— 7.1.4p1 C18 标准。
评论
0赞
Konrad Rudolph
5/11/2023
你有成为UB的参考吗?我手头没有当前的 C 标准文档,但据我所知,旧版本并没有这么说(除非我忽略了所有库函数都需要有效指针的措辞)。fclose(NULL)
0赞
Harith
5/12/2023
@KonradRudolph 我添加了相关规则。
评论
fclose(NULL)
printf(...)
printf("File \"file2.bin\" inexistent!");
fopen
fopen
fopen
perror(path)
fopen
errno