26

マニュアルページによるとfclose(3)

戻り値

正常に完了すると 0 が返されます。それ以外の場合はEOFが返され、エラーを示すためにグローバル変数errnoが設定されます。どちらの場合でもfclose()、ストリームへのさらなるアクセス ( への別の呼び出しを含む) は、未定義の動作を引き起こします。

エラー

EBADF基礎となるファイル記述子fpが無効です。

fclose()関数が失敗errnoし、ルーチンclose(2)に指定されたエラーのいずれwrite(2)かが設定される場合もありますfflush(3)

もちろん失敗するはずですが、セグメンテーションフォルトで直接死ぬのではなくfclose(NULL)、正常に戻ることを期待しています。errnoこの動作の理由はありますか?

前もって感謝します。

更新:ここにコードを配置します(特に試していますstrerror())。

FILE *not_exist = NULL;

not_exist = fopen("nonexist", "r");
if(not_exist == NULL){
    printError(errno);
}

if(fclose(not_exist) == EOF){
    printError(errno);
}
4

5 に答える 5

36

fclose引数として、、標準ストリーム、、またはのFILEいずれかによって取得されるポインタ、またはその他の実装定義の方法で取得されるポインタが必要です。null ポインターはこれらのいずれでもないため、動作は未定義です。NULL はCでは特別ではありません。有効なポインターと等しくないことを比較することが保証されているという事実を除けば、それは他の無効なポインターとまったく同じであり、それを使用すると未定義の動作が呼び出されます。それには特別な意味があります。fopenstdinstdoutstderrfclose((FILE *)0xdeadbeef)NULL

さらに、エラーを返すことは有効ですが (動作はとにかく未定義であるため) 、未定義の動作が隠されるため、実装にとって有害な動作になります。未定義の動作を呼び出すことの望ましい結果は、エラーを強調表示して修正できるようにするため、常にクラッシュです。のほとんどのユーザーは、エラーの戻り値をチェックしません。また、 に渡すほど愚かなほとんどの人は、 の戻り値をチェックするほど賢くはないだろうとfclose私は賭けます。最終的なフラッシュが失敗する可能性があるため、一般的にの戻り値をチェックする必要があるという議論がなされる可能性がありますが、これは、読み取り専用に開かれているファイルや、以前に手動で呼び出された場合には必要ありません。NULLfclosefclosefclosefflushfclose(とにかく、ファイルを開いたままにしておくとエラーを処理しやすいため、これはよりスマートなイディオムです)。

于 2013-06-04T16:25:35.040 に答える
6

マニュアル ページで説明されているエラーは、プログラミング エラーではなくランタイム エラーです。NULLポインタを期待する API に渡すだけで、その API が適切な処理を行うことを期待することはできません。NULLデータへのポインターを要求することが文書化されている関数へのポインターを渡すことはバグです。

関連する質問: C または C++ のいずれかで、ポインター パラメーターを NULL/nullptr に対してチェックする必要がありますか?

その質問に対する回答の 1 つに関するR. のコメントを引用するには、次のようにします。

...動作環境の例外的な状態 (fs フル、メモリ不足、ネットワーク ダウンなど) から発生するエラーとプログラミング エラーを混同しているようです。前者の場合、もちろん、堅牢なプログラムはそれらを適切に処理できる必要があります。後者では、堅牢なプログラムはそもそもそれらを経験できません。

于 2013-06-04T16:31:29.847 に答える
3

このfclose()問題は FreeBSD の遺産のようであり、Microsoft と Linux の両陣営によって無批判に受け入れられました。

一方、HP、SGI、Solaris、および CYGWIN はすべて適切に処理されfclose(NULL)ます。たとえばman fclose、OPのglibcではなくnewlibを使用するCYGWINの場合、次のように述べています。

成功した場合、fclose は 0 を返します (FP が NULL であるか、開いているファイルでない場合を含む)。

関連する議論については、https://stackoverflow.com/a/8442421/318716を参照してください。

于 2013-06-04T16:39:23.270 に答える
1

マンページでは、に渡すファイルポインタではなく、基になるファイル記述子open(を呼び出したときにシステムコールを介して内部的に取得されるものfopen) が無効であると述べていると思います。fclose

于 2013-06-04T16:43:37.693 に答える