根据手册页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);
}
答案 0 :(得分:25)
fclose
需要FILE
指针作为参数,fopen
指针由stdin
,标准流stdout
,stderr
或{{1}之一获得},或者以其他一些实现定义的方式。空指针不是其中之一,因此行为未定义,就像fclose((FILE *)0xdeadbeef)
一样。 C中的 NULL并不特殊;除了保证比较不等于任何有效指针的事实之外,它就像任何其他无效指针一样,并且使用它会调用未定义的行为,除非你将它作为合同的一部分传递给文档的接口{{ 1}}对它有一些特殊的意义。
此外,返回错误将是有效的(因为行为未定义)但是对于实现有害的行为,因为它隐藏了未定义的行为。调用未定义行为的最佳结果始终是崩溃,因为它突出显示错误并使您能够修复它。 NULL
的大多数用户都没有检查错误返回值,我敢打赌,大多数愚蠢到将fclose
传递给NULL
的人都不够聪明,无法检查fclose
的返回值。可以提出一个论点,即人们应检查fclose
的返回值,因为最后的刷新可能会失败,但对于仅为阅读而打开的文件而言,这不是必需的,或者如果在fclose
之前手动调用fflush
(这是一个更聪明的习惯用法,因为在你打开文件时更容易处理错误)。
答案 1 :(得分:6)
fclose(NULL)
应该成功。 free(NULL)
成功,因为这样可以更容易编写清理代码。
令人遗憾的是,这不是它的定义方式。因此,您无法在便携式程序中使用fclose(NULL)
。 (例如,见http://pubs.opengroup.org/onlinepubs/9699919799/)。
正如其他人所提到的,如果将NULL传递给错误的地方,通常不需要返回错误。您需要一条警告消息,至少在调试/测试版本上是这样。解除引用NULL会立即给出警告消息,并有机会收集标识编程错误的回溯:)。在编程时,段错误是您可以获得的最佳错误。 C有许多细微的错误,调试需要更长的时间......
可以滥用错误返回以增加编程错误的稳健性。但是,如果您担心软件崩溃会丢失数据,请注意可能会发生完全相同的情况。如果您的硬件断电这就是为什么我们有自动保存(since Unix text editors with two-letter names like ex and vi)。您的软件可能会明显崩溃,而不是继续处于不一致的状态。
答案 2 :(得分:4)
手册页所讨论的错误是运行时错误,而不是编程错误。您不能只将NULL
传递给任何期望指针的API,并期望API做一些合理的事情。将NULL
指针传递给记录的函数需要指向数据的指针是一个错误。
相关问题:In either C or C++, should I check pointer parameters against NULL/nullptr?
引用R.'s comment对该问题的一个答案:
...您似乎混淆了由于编程错误导致的操作环境中的异常情况(fs已满,内存不足,网络中断等)引起的错误。在前一种情况下,一个强大的程序当然需要能够优雅地处理它们。在后者中,一个强大的程序首先无法体验它们。
答案 3 :(得分:1)
这个fclose()
问题似乎是FreeBSD的遗留问题,并被微软和Linux阵营不加批判地接受。
但另一方面,HP,SGI,Solaris和CYGWIN都合理地处理fclose(NULL)
。例如,CYGWIN的man fclose
使用newlib而不是OP的glibc,声明:
fclose returns 0 if successful (including when FP is NULL or not an open file)
有关相关讨论,请参阅https://stackoverflow.com/a/8442421/318716。
答案 4 :(得分:1)
我认为该联机帮助页讨论了基础文件描述符(当您调用open
时,fopen
系统调用内部获取的文件描述符无效)您传递给fclose
的文件指针。