web-dev-qa-db-ja.com

Cプログラムでfclose()を呼び出さないとどうなりますか?

第一に、fopen()でファイルを開き、閉じないことは恐ろしく無責任で、悪い形式であることを認識しています。これは単なる好奇心ですので、私をユーモアにしてください:)

Cプログラムが多数のファイルを開き、それらのいずれも閉じない場合、最終的にfopen()が失敗し始めることを知っています。コード自体の外で問題を引き起こす可能性のある他の副作用はありますか?たとえば、1つのファイルを開き、閉じずに終了するプログラムがある場合、プログラムを実行している人に問題が発生する可能性がありますか?そのようなプログラムは何か(メモリ、ファイルハンドル)をリークしますか?プログラムが終了すると、そのファイルに再度アクセスする際に問題が発生する可能性はありますか?プログラムが連続して何度も実行されるとどうなりますか?

56
electrodruid

プログラムを実行している限り、ファイルを閉じずに開いたままにしておくと、最も可能性の高い結果は、プロセスで使用可能なファイル記述子/ハンドルを使い果たし、さらにファイルを開こうとすると失敗します。 Windowsでは、これにより、他のプロセスが開いているファイルを開いたり削除したりするのを防ぐことができます。デフォルトでは、ファイルは他のプロセスが開かない排他共有モードで開かれるためです。

プログラムが終了すると、オペレーティングシステムがクリーンアップします。プロセスを終了するときに開いたままのファイルをすべて閉じ、必要なその他のクリーンアップを実行します(たとえば、ファイルが閉じるときに削除とマークされている場合、ファイルを削除します;そのようなことはプラットフォームであることに注意してください) -特定)。

ただし、注意が必要な別の問題は、バッファリングされたデータです。ほとんどのファイルストリームは、ディスクに書き込む前にデータをメモリにバッファします。 stdioライブラリの_FILE*_ストリームを使用している場合、2つの可能性があります。

  1. exit(3) 関数を呼び出すか、main(暗黙的にexit(3)を呼び出す)から戻ることにより、プログラムは正常に終了しました。
  2. プログラムが異常終了しました。これは、 abort(3) または _Exit(3) の呼び出し、シグナル/例外などで終了するなどの方法で行うことができます。

プログラムが正常に終了した場合、Cランタイムは、開いていたバッファされたストリームをフラッシュします。そのため、フラッシュされていない_FILE*_に書き込まれたデータをバッファリングした場合、通常の終了時にフラッシュされます。

逆に、プログラムが異常終了した場合、バッファされたデータはnotフラッシュされません。 OSは、プロセスが終了すると、「ああ、親愛なる、ファイル記述子を開いたままにしておいた方がよい。」とだけ言っています。プログラムがディスクへの書き込みを意図していたが、そうではなかったランダムなデータがメモリのどこかにあるとは考えられません。そのため、注意してください。

76
Adam Rosenfield

C標準では、exitを呼び出す(または、同等にmainから戻る)と、開いているすべてのFILEオブジェクトがfcloseによってas-ifで閉じられるとされています。したがって、書き込みエラーを検出する機会を失うことを除いて、これはまったく問題ありません。

編集:abnormal終了(abort、失敗したassert、デフォルトの振る舞いがプログラムを異常終了させるシグナル-そのようなシグナルは必ずしも存在しないことに注意してください-および他の実装定義の手段)。他の人が言ったように、最新のオペレーティングシステムは、OSレベルのファイルハンドルを開くなど、すべてのexternally visibleリソースをクリーンアップします。ただし、FILEsはnotであり、その場合はフラッシュされる可能性があります。

異常終了時に外部から見えるリソースをクリーンアップしなかったOSは確かにありました。 「カーネル」と「ユーザー」コード間、および/または個別のユーザー空間「プロセス」間でハード特権境界を強制しない傾向があります。単に、これらの境界がない場合は、possibleすべての場合に安全に行います。 (たとえば、MS-DOSでオープンファイルテーブルにガベージを書き込むとどうなるかを考えてください。完全にできるようになっています。)

13
zwol

exit() システムコールを使用するか、main()から戻ることにより、制御下で終了すると仮定すると、開いているファイルストリームはフラッシュ後に閉じられます。 C標準(およびPOSIX)はこれを義務付けています。

制御不能(コアダンプ、SIGKILL)などで終了した場合、または _exit()または_Exit() を使用した場合、開いているファイルストリームはフラッシュされません(しかし、ファイル記述子はPOSIXのようなシステムでファイル記述子を使用していると仮定すると、閉じられます-標準Cはファイル記述子を強制しません)。 _Exit()はC99標準で義務付けられていますが、_exit()はPOSIXで義務付けられています(ただし、POSIXシステムでも同じように動作します)。ファイル記述子はファイルストリームとは別のものであることに注意してください。 _exit()については、POSIXページの「プログラム終了の結果」の説明を参照して、Unixでプログラムが終了するとどうなるかを確認してください。

5

プロセスが終了すると、最新のオペレーティングシステム(特にカーネル)は、すべてのハンドルと割り当てられたメモリを解放します。

0
Peter