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

2024-11-14 08:29:00
admin
原创
15
摘要:问题描述:根据手册页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

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

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

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

内置subversion和git源码管理

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

免费试用