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

2024-11-14 08:29:00
admin
原创
147
摘要:问题描述:根据手册页fclose(3):返回值成功完成后,将返回 0。否则,EOF将返回 并设置全局变量errno以指示错误。无论哪种情况,fclose()对流的任何进一步访问(包括对 的另一次调用)都会导致未定义的行为。错误EBADF底层文件描述符fp无效。该fclose()函数也可能失败,并设置errno...

问题描述:

根据手册页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);
}

解决方案 1:

fclose`FILE需要通过fopen、标准流stdinstdout或之一stderr或其他实现定义的方式获得的指针作为其参数。空指针不是其中之一,因此行为未定义,就像fclose((FILE *)0xdeadbeef)会一样。NULL在 C 中**并不特殊**;除了它保证与任何有效指针的比较不相等之外,它就像任何其他无效指针一样,并且使用它会调用未定义的行为,除非您将其传递给的接口作为其合同的一部分记录,并且该合同NULL`对它具有某些特殊含义。

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

解决方案 2:

fclose(NULL) 应该会成功。 free(NULL)成功,因为这使得编写清理代码变得更容易。

遗憾的是,它的定义并非如此。因此您无法fclose(NULL)在可移植程序中使用。(例如,请参阅http://pubs.opengroup.org/onlinepubs/9699919799/)。

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

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

解决方案 3:

手册页中提到的错误是运行时错误,而不是编程错误。您不能直接将NULL指针传递给任何需要指针的 API,并期望该 API 执行合理的操作。将指针传递NULL给记录为需要指向数据的指针的函数是一个错误。

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

引用R.对这个问题的一个答案的评论:

...您似乎将操作环境中的异常情况(文件系统已满、内存不足、网络中断等)导致的错误与编程错误混淆了。在前一种情况下,健壮的程序当然需要能够妥善处理它们。在后一种情况下,健壮的程序首先就无法遇到它们。

解决方案 4:

这个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了解相关讨论。

解决方案 5:

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

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1120  
  IPD(Integrated Product Development,集成产品开发)流程是一种广泛应用于高科技和制造业的产品开发方法论。它通过跨职能团队的紧密协作,将产品开发周期缩短,同时提高产品质量和市场成功率。在IPD流程中,CDCP(Concept Decision Checkpoint,概念决策检查点)是一个关...
IPD培训课程   75  
  研发IPD(集成产品开发)流程作为一种系统化的产品开发方法,已经在许多行业中得到广泛应用。它不仅能够提升产品开发的效率和质量,还能够通过优化流程和资源分配,显著提高客户满意度。客户满意度是企业长期成功的关键因素之一,而IPD流程通过其独特的结构和机制,能够确保产品从概念到市场交付的每个环节都围绕客户需求展开。本文将深入...
IPD流程   66  
  IPD(Integrated Product Development,集成产品开发)流程是一种以跨职能团队协作为核心的产品开发方法,旨在通过优化资源分配、提高沟通效率以及减少返工,从而缩短项目周期并提升产品质量。随着企业对产品上市速度的要求越来越高,IPD流程的应用价值愈发凸显。通过整合产品开发过程中的各个环节,IPD...
IPD项目管理咨询   76  
  跨部门沟通是企业运营中不可或缺的一环,尤其在复杂的产品开发过程中,不同部门之间的协作效率直接影响项目的成败。集成产品开发(IPD)作为一种系统化的项目管理方法,旨在通过优化流程和增强团队协作来提升产品开发的效率和质量。然而,跨部门沟通的复杂性往往成为IPD实施中的一大挑战。部门之间的目标差异、信息不对称以及沟通渠道不畅...
IPD是什么意思   70  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用