在退出时关闭文件描述符是一个好习惯

时间:2013-03-06 12:01:12

标签: c coding-style file-descriptor

如果由于某种原因,我发现我的程序中有致命的情况,我想退出错误代码。 有时,致命错误的上下文超出了其他文件描述符的范围。 关闭这些文件描述符是一个好习惯。 据我所知,当进程终止时,这些文件会自动关闭。

6 个答案:

答案 0 :(得分:14)

文件会自动关闭,但这是一种很好的做法。

参见本例中的valgrind

david@debian:~$ cat demo.c
#include <stdio.h>

int main(void)
{
    FILE *f;

    f = fopen("demo.c", "r");
    return 0;
}
david@debian:~$ valgrind ./demo
==3959== Memcheck, a memory error detector
==3959== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==3959== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
==3959== Command: ./demo
==3959== 
==3959== 
==3959== HEAP SUMMARY:
==3959==     in use at exit: 568 bytes in 1 blocks
==3959==   total heap usage: 1 allocs, 0 frees, 568 bytes allocated
==3959== 
==3959== LEAK SUMMARY:
==3959==    definitely lost: 0 bytes in 0 blocks
==3959==    indirectly lost: 0 bytes in 0 blocks
==3959==      possibly lost: 0 bytes in 0 blocks
==3959==    still reachable: 568 bytes in 1 blocks
==3959==         suppressed: 0 bytes in 0 blocks
==3959== Rerun with --leak-check=full to see details of leaked memory
==3959== 
==3959== For counts of detected and suppressed errors, rerun with: -v
==3959== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 4)

如您所见,它会引发内存泄漏

在某些情况下,您可以使用atexit()

#include <stdio.h>
#include <stdlib.h>

static FILE *f;

static void free_all(void)
{
    fclose(f);
}

static int check(void)
{
    return 0;
}

int main(void)
{
    atexit(free_all);
    f = fopen("demo.c", "r");
    if (!check()) exit(EXIT_FAILURE);
    /* more code */
    return 0;
}

答案 1 :(得分:8)

POSIX编程的经典指南“UNIX环境中的高级编程”声明:

  

当进程终止时,内核会自动关闭其所有打开的文件。许多程序利用了这一事实,并没有明确关闭打开的文件。

你没有在你的问题中提到操作系统,但是应该从任何操作系统中获得这样的行为。只要您的程序控制流程从exit()越过returnmain(),系统就有责任在流程结束后进行清理。

OS实施中总是存在错误的危险。但是,另一方面,系统必须在进程终止时解除分配多个打开文件描述符的方式:可执行文件映像,堆栈,与进程关联的内核对象占用的内存。您无法从用户空间控制此行为,只需依靠其按预期工作即可。那么,为什么程序员不能依赖fd s的自动关闭?

因此,将fd打开的唯一问题可能是编程风格问题。并且,就像使用stdio对象(即围绕系统提供的文件i / o构建的东西)的情况一样,在valgrinding时你可能会(有些)迷惑警报。至于泄漏系统资源的危险,除非你的操作系统实现真的有问题,否则不用担心。

答案 2 :(得分:4)

  

据我所知,当进程终止时,这些文件会自动关闭。

不要依赖于此。从概念上讲,当进程终止时,释放已分配的内存,关闭非标准文件描述符等是您的责任。当然,每个理智的操作系统(甚至Windows)都会在您的进程后清理,但这不是我们所期待的。

答案 3 :(得分:2)

是。假设您的主程序现在是一个单独程序中的类。现在您刚刚描述了资源泄漏。你基本上是依赖于全局程序状态,即进程的状态 - 不是你的模块,不是类,不是ADT,而不是线程,而是整个进程 - 处于关闭状态,从而违反封装。

答案 4 :(得分:1)

如果您的程序正常终止(例如,通过exit或从main返回),则可以保证所有打开的文件都会关闭。但是,如果您的程序异常终止,例如由于使用了NULL指针,它被操作系统关闭,由操作系统关闭文件。因此,如果文件在意外终止时不再需要,请确保文件已关闭。

另一个原因是资源限制。大多数操作系统都限制打开的文件数量(以及许多其他内容),因此最好在不再需要这些资源时立即返回这些资源。如果每个程序都无限期地打开所有文件,那么系统很快就会遇到问题。

答案 5 :(得分:1)

每个理智的操作系统(当然任何形式的Linux或Windows)都会在程序终止时关闭文件。如果你有一个非常简单的程序,那么你可能不需要在终止时关闭文件。但是,明确关闭文件仍然是一种很好的做法,原因如下:

  1. 如果将其保留在操作系统中,则无法控制文件关闭的顺序,这可能会导致一致性问题(例如在多文件数据库中)。

  2. 如果关闭文件时出现错误(例如I / O错误,空间错误等),则无法报告。

  3. 可能存在需要处理的文件锁定交互。

  4. 关闭所有文件的例程可以处理程序同时需要的任何其他清理(例如,刷新缓冲区)