7

そのため、libc の stdio 部分がどのように実装されているかを調べていて、別の質問に出くわしました。見るとman setvbuf、次のように見えます。

ファイルに対して最初の I/O 操作が発生すると、malloc(3) が呼び出され、バッファが取得されます。

これは理にかなっていmallocます。実際に使用しない限り、プログラムに I/O 用の を含めるべきではありません。これに対する私の直感的な反応は、libc がここで独自の混乱を解消するということです。これは、valgrind がメモリ リークを報告していないためだと思います (もちろん、何か汚いことをして、malloc直接割り当てないこともできます... しかし、今のところ文字通り使用していると仮定しますmalloc)。

ただし、独自のバッファも指定できます...

int main() {
    char *p = malloc(100);
    setvbuf(stdio, p, _IOFBF, 100);
    puts("hello world");
}

いやいや、メモリリーク!valgrind はそれを確認します。そのため、stdio が独自にバッファーを割り当てるたびに、自動的に削除されるようです (遅くともプログラムの終了時ですが、おそらくストリームの終了時)。ただし、バッファーを明示的に指定する場合は、自分でクリーンアップする必要があります。

ただし、キャッチがあります。マニュアルページには次のようにも書かれています:

ストリームが閉じられるまでに buf が指す領域がまだ存在していることを確認する必要があります。これは、プログラムの終了時にも発生します。たとえば、次は無効です。

現在、これは標準ストリームにとって興味深いものになっています。それらはプログラムの終了時に閉じられるため、手動で割り当てられたバッファーをどのように適切にクリーンアップしますか? ファイル構造内で「フラグを閉じるときにこれをクリーンアップする」ことを想像できますが、これを正しく読むと次のようなことを行うため、毛むくじゃらになります。

setvbuf(stdout, 0, _IOFBF, 0);
printf("hello ");
setvbuf(stdout, 0, _IOLBF, 0);
printf("world\n");

次の文のために、標準ライブラリによって 2 つの割り当てが発生します。

引数 buf が NULL の場合、モードのみが影響を受けます。次の読み取りまたは書き込み操作で新しいバッファが割り当てられます。

編集:私の質問への補遺。freeに渡すバッファが必要であることは明らかなのでsetvbuf、実際に使用する場合stdout、実用的な方法はありますfreeか? プログラムの終了まで存続する必要があります。私が考えることができる最善の方法はfclose(stdout)、一部の人が言及したように、それを解放するか、静的バッファーを使用することです。それは厄介な設計上の決定のように思えるので、私は尋ねます.

4

3 に答える 3

3

少なくともC標準によれば、最後のシナリオは単純に許可されていません。「setvbuf関数は、ストリームが指すストリームが開いているファイルに関連付けられた後、他の操作(呼び出しの失敗以外)の前にのみ使用できます。 to setvbuf)はストリームで実行されます。」(C99、§7.19.5.6/ 2)。

より単純なケースでいつメモリを解放するかについては、途中でコールバックを呼び出して、を終了した後、制御がOSに戻る前にatexit()メモリを解放するコールバックを登録します。main()

于 2010-04-19T22:02:43.877 に答える
3

また、マニュアルページから(少なくとも、私のシステムでは):

buf が NULL でない場合、ストリームを閉じた後にこのバッファを free(3) するのは呼び出し元の責任です。

つまり、それを malloc したり、解放したりします。

終了する前に、ストリームを自分で閉じることができるため、バッファを解放できます。または、ストリームをフラッシュsetvbufし、バッファ引数を指定して再度呼び出しNULLて、ライブラリ管理バッファまたはバッファリングされていない I/O に戻すこともできます。

于 2010-04-19T21:48:14.250 に答える
1

stdinstdoutおよびstderr明示的に ( を使用して)閉じることができますfclose()

ほとんどのオペレーティング システムでは、ヒープ メモリはプログラムの終了時に自動的に解放されます。したがって、解放されていないバッファを使用しても実際的な問題はありません (これらの解放されていないバッファが Valgrind の出力を汚染するという表面的な問題があります)。setvbuf()標準入力または標準出力を呼び出したい場合は、静的バッファーを使用することをお勧めします。標準ストリームは 3 つしかなく、これらのストリームがプログラムの終了まで開いたままになる状況を心配しているため、静的バッファーを割り当てたり解放したりする必要はありません。

于 2010-04-19T21:53:20.933 に答える