2

「Cの罠と落とし穴」PDF)の第5章にある例を見ています。

#include <stdio.h>

main()
{
    int c;

    char buf[BUFSIZ];
    setbuf(stdout, buf);

    while ((c = getchar()) != EOF)
        putchar(c);
}

残念ながら、このプログラムは微妙な理由で間違っています。問題がどこにあるかを確認するには、バッファが最後にフラッシュされたのはいつかを尋ねます。

回答:メインプログラムが終了した後、ライブラリがオペレーティングシステムに制御を戻す前に行うクリーンアップの一環として、しかしその時点で、バッファはすでに解放されています!

mainは、スタックと変数をクリーンアップする必要がある関数です。しかし、それはどういう意味ですか:バッファはすでに解放されていますか?

理解するのは難しいと思います。誰かがそれを詳細に説明できますか?前もって感謝します。

4

2 に答える 2

2

これは、バッファがスコープに入った場所(定義された場所)からスコープ外になるポイント(最後)までしか使用できないことを意味し}ます。

その後のバッファの使用は未定義の動作です。標準出力のフラッシュでは、出力文字をバッファリングする場所であるため、必然的にそのバッファが使用されます。

したがって、問題-フラッシュが実行される前にバッファが再利用されたメモリ領域が存在する可能性があります(Cランタイム環境のシャットダウンコードの複雑さによって異なります)。

終了後に他の用途に使用されないスタックの一部を使用する場合は、正常に機能しているように見えるかもしれませんが、まったく機能しない可能性mainがあるという事実は、それを良い考えにします。

あなたが引用するその特定の本はかなり古いですが、これは現在のC11標準でもまだ問題です。setbuf詳細とsetvbuf:のセクションで

バッファーの存続期間は、少なくともオープンストリームと同じである必要があるため、ブロックの終了時に自動ストレージ期間を持つバッファーの割り当てが解除される前に、ストリームを閉じる必要があります。

于 2012-05-31T02:21:33.357 に答える
2

setbufスタックにバッファを割り当ててから、「今後はこのバッファを使用する」と呼び出しstdoutます。

後でmain戻ると、そのスタック フレーム ( のメモリを含むbuf) はスタックから削除されますがstdout、そのアドレスのメモリはまだ使用されています。問題は、メモリが他の誰か (C ランタイムのシャットダウン コード、割り込みなど) によって再利用される可能性があり、C ランタイムがstdoutのバッファをフラッシュする前に、メモリが他のデータで上書きされる可能性があることです。

(個人的には、「解放された」という用語を、リターン時に何が起こるかを指すのに使用しません。bufmainフリー」という言葉は、通常、スタック割り当てではなく、ヒープ割り当てを指します。もうあなたのものではありません。)mainbuf

問題のより鮮明な例については、スコープ外でのローカル変数のメモリの使用に関するEric Lippert の回答を参照してください。あなたの例と同じ問題です。

于 2012-05-31T02:36:53.663 に答える