为什么glibc的fclose(NULL)会导致分段错误而不是返回错误?

Vdr*_*gon 19 c linux segmentation-fault fclose

根据手册页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);
}
Run Code Online (Sandbox Code Playgroud)

R..*_*R.. 27

fclose要求作为其参数一个FILE指针获得或者通过fopen,标准流中的一个stdin,stdoutstderr,或在一些其它实现定义方式.空指针不是其中之一,因此行为是未定义的,就像那样fclose((FILE *)0xdeadbeef).NULL在C中并不特殊 ; 除了一个事实,即它保证比较不等于任何有效的指针,它只是像任何其他无效的指针,并使用它调用时的界面你将它传递给文件作为合同的一部分,除了不确定的行为NULL具有一定的它的特殊含义.

此外,返回错误将是有效的(因为行为未定义),但实现的有害行为,因为它隐藏了未定义的行为.调用未定义行为的最佳结果始终是崩溃,因为它突出显示错误并使您能够修复它.大多数用户fclose都没有检查错误返回值,而且我打赌大多数人愚蠢地传递NULL给他们fclose并不会足够聪明地检查返回值fclose.一种说法可以提出,人们应该检查返回值fclose在一般情况下,因为最后的冲洗可能会失败,但是这是没有必要的是仅进行读取操作,或者如果文件fflush手动之前被称为fclose(这是一个聪明的成语呢因为在你打开文件时更容易处理错误.

  • 有趣的是,对于`malloc` /`free`没有遵循这个推理,其中释放空指针是完全正常的.不一致... (9认同)
  • @Thomas:`free` 接受空指针的要求不是一个实现选择;这是语言规定的。有些人声称此要求与允许 `malloc(0)` 在成功时返回空指针这一事实有关,但我还没有看到任何官方确认该声明。 (3认同)
  • 我想的问题是,为什么C标准没有使`fclose(0);`成为无操作对象,就像`free(0);`一样。当然,这不会破坏任何现有代码或引起任何不良情况。 (3认同)
  • 该语句在普通阅读中是不正确的:“ ...空指针不是其中之一...”这是不正确的。空指针是当无法打开文件时由`fopen`返回的指针。附带说明一下,`fclose`可以接受空指针,pointer,Standard不需要它。 (2认同)

sou*_*edi 9

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

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

正如其他人提到的那样,如果将NULL传递到错误的位置,通常不希望返回错误。您至少在调试/测试版本中需要警告消息。取消引用NULL会给您立即警告消息,并有机会收集可识别编程错误的回溯信息:)。在编程时,段错误就是您可能会遇到的最佳错误。C还有许多细微的错误,需要花费更长的时间进行调试...

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


Bil*_*eal 6

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

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

引用R.对该问题的答案之一的评论

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


Jos*_*sey 5

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

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

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

有关相关讨论,请参阅/sf/answers/590969501/ 。

  • 如果“合理”是“隐藏表现出未定义行为的完全损坏的代码”,那么我认为这是合理的。 (2认同)