76

首先,我知道用 fopen() 打开一个文件而不关闭它是非常不负责任和糟糕的形式。这只是纯粹的好奇心,所以请幽默我:)

我知道如果一个 C 程序打开一堆文件并且从不关闭其中任何一个,最终 fopen() 将开始失败。是否有任何其他副作用可能导致代码本身之外的问题?例如,如果我有一个程序打开一个文件,然后在没有关闭它的情况下退出,这会对运行该程序的人造成问题吗?这样的程序会泄漏任何东西(内存、文件句柄)吗?程序完成后再次访问该文件是否会出现问题?如果程序连续运行多次会发生什么?

4

4 回答 4

100

只要您的程序正在运行,如果您一直打开文件而不关闭它们,最有可能的结果是您将用完可用于您的进程的文件描述符/句柄,并且尝试打开更多文件最终将失败。在 Windows 上,这还可以防止其他进程打开或删除您打开的文件,因为默认情况下,文件以独占共享模式打开,从而阻止其他进程打开它们。

一旦您的程序退出,操作系统将在您之后进行清理。它会在终止进程时关闭您打开的所有文件,并执行任何其他必要的清理(例如,如果文件被标记为关闭时删除,那么它将删除该文件;请注意,这种事情是平台-具体的)。

但是,另一个需要注意的问题是缓冲数据。大多数文件流在将数据写入磁盘之前先在内存中缓冲数据。如果您使用FILE*stdio 库中的流,则有两种可能性:

  1. 您的程序通过调用exit(3)函数或从main(隐式调用exit(3))返回正常退出。
  2. 你的程序异常退出;这可以通过调用abort(3)or _Exit(3),死于信号/异常等。

如果您的程序正常退出,C 运行时将负责刷新任何打开的缓冲流。因此,如果您将缓冲数据写入FILE*未刷新的 a,它将在正常退出时刷新。

相反,如果你的程序异常退出,任何缓冲的数据都不会被刷新。当进程终止时,操作系统只会说“哦,天哪,你打开了一个文件描述符,我最好为你关闭它”;它不知道程序打算写入磁盘但没有写入内存中某处的一些随机数据。所以要小心。

于 2011-11-17T23:49:19.527 回答
13

C 标准说调用exit(或等效地,从 中返回main)会导致所有打开FILE的对象被关闭fclose。所以这完全没问题,只是你失去了检测写入错误的机会。

编辑:对于异常终止没有这样的保证(abort,一个 failed assert,接收到一个默认行为是异常终止程序的信号 - 请注意,不一定有任何这样的信号 - 以及其他实现定义的方式)。正如其他人所说,现代操作系统将清理所有外部可见的资源,例如打开的操作系统级文件句柄,无论如何;但是,在这种情况下, FILEs 可能不会被刷新。

肯定有一些操作系统在异常终止时没有清理外部可见的资源;它倾向于不强制执行“内核”和“用户”代码之间和/或不同用户空间“进程”之间的硬权限边界,仅仅是因为如果你没有这些边界,可能无法安全地这样做在所有情况下。(例如,考虑一下,如果你在 MS-DOS 中的打开文件表上写垃圾会发生什么,你完全可以做到。)

于 2011-11-17T23:42:45.890 回答
5

假设您在控制下退出,使用exit()系统调用或从返回main(),则打开的文件流在刷新后关闭。C 标准(和 POSIX)要求这样做。

如果您退出失控(核心转储,SIGKILL)等,或者如果您使用_exit()or_Exit(),则打开的文件流不会被刷新(但文件描述符最终会关闭,假设具有文件描述符的类似 POSIX 的系统 - 标准 C 确实如此不强制文件描述符)。请注意,这_Exit()是 C99 标准规定的,但_exit()POSIX 规定的(但它们在 POSIX 系统上的行为相同)。请注意,文件描述符与文件流是分开的。请参阅 POSIX 页面上“程序终止的后果”的讨论,_exit()以了解在 Unix 下程序终止时会发生什么。

于 2011-11-17T23:43:27.987 回答
0

当进程终止时,大多数现代操作系统(特别是内核)将释放所有句柄和分配的内存。

于 2011-11-17T23:28:24.770 回答