如果由于某种原因,我发现程序中存在致命情况,并且我想退出并显示错误代码。 有时,致命错误的上下文超出了其他文件描述符的范围。
关闭这些文件描述符是一个好习惯吗?
据我所知,当进程终止时,这些文件会自动关闭。
POSIX编程经典指南《UNIX环境下的高级编程》指出:
当进程终止时,内核会自动关闭其所有打开的文件。许多程序利用这一事实并且不显式关闭打开的文件。
您在问题中没有提到操作系统,但任何操作系统都应该出现这种行为。每当您的程序控制流从
exit()
穿过 return
或 main()
时,系统就有责任在流程结束后进行清理。
操作系统实施中始终存在错误的危险。但是,另一方面,系统必须在进程终止时释放多个打开的文件描述符:与进程关联的可执行文件映像、堆栈、内核对象占用的内存。您无法从用户空间控制此行为,您只能依赖其按预期工作。那么,为什么程序员不能依赖
fd
的自动关闭呢?
因此,保持
fd
开放的唯一问题可能是编程风格问题。而且,就像使用 stdio
对象(即围绕系统提供的文件 I/O 构建的东西)一样,您可能会在 valgrinding 时收到(有些)令人迷失方向的警报。至于泄漏系统资源的危险,应该没有什么可担心的,除非你的操作系统实现确实有错误。
文件会自动关闭,但这是一个很好的做法。
参见 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;
}
据我所知,当进程终止时,这些文件会自动关闭。
不要依赖它。从概念上讲,当进程终止时,释放分配的内存、关闭非标准文件描述符等是“你的责任”。当然,每个正常的操作系统(甚至 Windows)都会在进程结束后进行清理,但这并不是什么事情期待。
exit
或从
main
返回),所有打开的文件都将被关闭。但是,如果您的程序异常终止,例如由于使用了 NULL 指针,它被操作系统关闭,由操作系统来关闭文件。因此,最好确保文件在不再需要时关闭,以防意外终止。另一个原因是资源限制。大多数操作系统对打开的文件数量(以及许多其他事情)都有限制,因此最好在不再需要这些资源时立即将其归还。如果每个程序都无限期地保持所有文件打开,系统可能很快就会遇到问题。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
char *bin = NULL;
char *_argv = NULL;
char *_envp = NULL;
void handler(void) {
execve(bin, &_argv, &_envp);
}
int main (int argc, char **argv, char **envp) {
bin = argv[0];
_argv = *argv;
_envp = *envp;
printf("program name: %s pid: %d\n", argv[0], getpid());
int fd = open(".", O_DIRECTORY);
sleep(1);
atexit(handler);
return 0;
}
在 WSL2 中使用 gcc 作为编译器进行测试。