26

根据手册页fclose(3)

返回值

成功完成后返回 0。否则,EOF返回并设置全局变量errno以指示错误。在任何一种情况下,对流的任何进一步访问(包括对 的另一个调用fclose())都会导致未定义的行为。

错误

EBADF底层文件描述符fp无效。

fclose()函数也可能失败并设置errno为例程指定的任何错误close(2)write(2)fflush(3)

当然fclose(NULL)应该失败,但我希望它errno正常返回,而不是直接因分段错误而死亡。这种行为有什么原因吗?

提前致谢。

更新:我将把我的代码放在这里(我正在尝试strerror(),特别是)。

FILE *not_exist = NULL;

not_exist = fopen("nonexist", "r");
if(not_exist == NULL){
    printError(errno);
}

if(fclose(not_exist) == EOF){
    printError(errno);
}
4

5 回答 5

36

fclose需要一个指针作为其参数,该FILE指针由fopen标准流之一stdin、、stdoutstderr、或以某种其他实现定义的方式获得。空指针不是其中之一,因此行为是未定义的,就像fclose((FILE *)0xdeadbeef)会一样。NULL 在 C 中并不特殊;除了保证与任何有效指针比较不等于这一事实之外,它就像任何其他无效指针一样,并且使用它会调用未定义的行为,除非您将接口作为其合同的一部分传递给文档时NULL有一些对它的特殊意义。

此外,返回错误将是有效的(因为无论如何行为是未定义的)但对实现有害的行为,因为它隐藏了未定义的行为。调用未定义行为的最佳结果始终是崩溃,因为它会突出显示错误并让您能够修复它。大多数用户fclose不检查错误返回值,我敢打赌,大多数愚蠢到被传递NULLfclose的人不会聪明到检查fclose. 可以提出一个论点,即人们应该检查一般的返回值fclose,因为最终刷新可能会失败,但这对于仅为读取而打开的文件或fflush之前手动调用的文件不是必需的fclose(无论如何,这是一个更聪明的习惯用法,因为在您仍然打开文件时更容易处理错误)。

于 2013-06-04T16:25:35.040 回答
12

fclose(NULL) 应该成功。 free(NULL)成功,因为这样可以更轻松地编写清理代码。

遗憾的是,它不是这样定义的。因此,您不能fclose(NULL)在可移植程序中使用。(例如参见http://pubs.opengroup.org/onlinepubs/9699919799/)。

正如其他人所提到的,如果您将 NULL 传递到错误的位置,您通常不希望返回错误。您需要一条警告消息,至少在调试/测试版本中。取消引用 NULL 会给您立即发出警告消息,并有机会收集标识编程错误的回溯:)。当你在编程时,段错误是你能得到的最好的错误。C 有许多更微妙的错误,这需要更长的时间来调试......

有可能滥用错误返回来提高对编程错误的鲁棒性。但是,如果您担心软件崩溃会丢失数据,请注意完全相同的情况,例如,如果您的硬件断电。这就是我们有自动保存的原因(因为 Unix 文本编辑器具有两个字母的名称,例如 ex 和 vi)。你的软件最好还是明显地崩溃,而不是继续处于不一致的状态。

于 2016-01-12T14:59:22.630 回答
6

手册页所讨论的错误是运行时错误,而不是编程错误。您不能只传入NULL任何期望指针的 API 并期望该 API 做一些合理的事情。将指针传递给NULL记录为需要数据指针的函数是一个错误。

相关问题:在 C 或 C++ 中,我应该根据 NULL/nullptr 检查指针参数吗?

引用R.对该问题的其中一个答案的评论:

...您似乎将由操作环境中的异常情况(fs 已满、内存不足、网络关闭等)引起的错误与编程错误混淆了。在前一种情况下,一个健壮的程序当然需要能够优雅地处理它们。在后者中,一个健壮的程序首先无法体验它们。

于 2013-06-04T16:31:29.847 回答
3

这个fclose()问题似乎是 FreeBSD 的遗留问题,并且被微软和 Linux 阵营不加批判地接受。

但另一方面,HP、SGI、Solaris 和 CYGWIN 都处理fclose(NULL)得当。例如,man fclose对于使用 newlib 而不是 OP 的 glibc 的 CYGWIN,声明:

fclose 如果成功则返回 0(包括当 FP 为 NULL 或不是打开的文件时)

有关相关讨论,请参阅https://stackoverflow.com/a/8442421/318716

于 2013-06-04T16:39:23.270 回答
1

我认为手册页讨论的是底层文件描述符open(当您调用时通过系统调用在内部获得的文件描述符fopen)无效,而不是您传递给的文件指针fclose

于 2013-06-04T16:43:37.693 回答