29

何らかの理由でプログラムに致命的な状況が見つかり、エラーコードで終了したい場合。致命的なエラーのコンテキストが他のファイル記述子の範囲外である場合があります。これらのファイル記述子を閉じるのは良い習慣ですか。私の知る限り、これらのファイルはプロセスが終了すると自動的に閉じられます。

4

6 に答える 6

17

ファイルは自動的に閉じられますが、これは良い習慣です。

この例の 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;
}
于 2013-03-06T12:06:27.480 に答える
16

POSIXプログラミングの古典的なガイド「UNIX環境での高度なプログラミング」には、次のように記載されています。

プロセスが終了すると、開いているすべてのファイルがカーネルによって自動的に閉じられます。多くのプログラムはこの事実を利用して、開いているファイルを明示的に閉じません。

質問でOSについて言及しませんでしたが、そのような動作はどのOSでも予想されるはずです。プログラムの制御フローが交差するexit()か、そこreturnから来るときはいつでもmain()、プロセス後にクリーンアップするのはシステムの責任です。

OS の実装には常にバグの危険があります。しかし一方で、システムは、プロセスの終了時に複数の開いているファイル記述子 (プロセスに関連付けられた実行可能ファイル イメージ、スタック、カーネル オブジェクトによって占有されているメモリ) の割り当てを解除する必要があります。ユーザー空間からこの動作を制御することはできません。意図したとおりに動作することに依存するだけです。では、なぜプログラマーはfds の自動終了に頼ることができないのでしょうか?

したがって、fds を開いたままにしておくことの唯一の問題は、プログラミング スタイルの問題かもしれません。また、stdioオブジェクト (つまり、システム提供のファイル I/O を中心に構築されたもの) を使用する場合と同様に、valgrind 中に (多少) 混乱するアラートが表示される場合があります。システム リソースのリークの危険性については、OS の実装に本当にバグがある場合を除き、心配する必要はありません。

于 2013-03-06T13:09:54.103 に答える
7

私の知る限り、これらのファイルはプロセスが終了すると自動的に閉じられます。

それに頼らないでください。概念的には、プロセスが終了したとき、割り当てられたメモリを解放したり、非標準のファイル記述子を閉じたりするのはあなたの責任です。

于 2013-03-06T12:04:28.100 に答える
3

はい。メイン プログラムが別のプログラムのクラスになったとします。これで、リソース リークについて説明しました。グローバルプログラムの状態、つまりプロセスの状態-モジュール、クラス、ADT、スレッドではなく、プロセス全体-がシャットダウン状態にあることに依存することにより、本質的にカプセル化に違反しています。

于 2013-03-06T12:06:48.227 に答える
2

C では、プログラムが正常に終了した場合 (つまり、exitまたは からの復帰main)、開いているすべてのファイルが閉じられることが保証されています。ただし、プログラムが異常終了した場合 (たとえば、NULL ポインターを使用したためにオペレーティング システムによってプログラムが閉じられた場合)、ファイルを閉じるのはオペレーティング システム次第です。したがって、予期しない終了に備えて、不要になったファイルを確実に閉じることをお勧めします。

もう 1 つの理由は、リソースの制限です。ほとんどのオペレーティング システムでは、開いているファイルの数 (および他の多くのもの) に制限があるため、それらのリソースが不要になったらすぐに返却することをお勧めします。すべてのプログラムがすべてのファイルを無期限に開いたままにしておくと、システムはすぐに問題に直面する可能性があります。

于 2013-03-06T13:16:38.943 に答える