10

Cでのスタックの振る舞いについて何か誤解しているのではないかと心配しています。

次のコードがあるとします。

int main (int argc, const char * argv[]) 
{
    int a = 20, b = 25;
    {
        int temp1;
        printf("&temp1 is %ld\n" , &temp1);
    }

    {
        int temp2;
        printf("&temp2 is %ld\n" , &temp2);
    }
    return 0;
}

両方のプリントアウトで同じアドレスを取得できないのはなぜですか?temp1がリサイクルされなかったかのように、temp2がtemp1から1int離れていることがわかりました。

私の期待は、スタックに20と25が含まれることです。次に、temp1を上に置き、次にそれを削除し、次にtemp2を上に置き、次にそれを削除します。

MacOSXでgccを使用しています。

最適化せずにコンパイルするために-O0フラグを使用していることに注意してください。

この質問の背景について疑問に思っている人:私はCの教材を準備しており、関数から自動変数へのポインターを返すことを避けるだけでなく、からの変数のアドレスを取得することも避けるべきであることを生徒に示しようとしています。ネストされたブロックとそれらを外部で逆参照します。これがどのように問題を引き起こすかを実証しようとしていたのですが、スクリーンショットを取得できませんでした。

4

6 に答える 6

19

コンパイラーは、最適化せずに同じ場所に配置する権利を完全に有しています。コンパイラが一度に1つのスタック操作のコードを生成してから何年も経ちました。最近では、スタックフレーム全体が一度にレイアウトされています。(数年前に同僚と私はこれを行うための特に賢い方法を考え出しました。)単純なスタックレイアウトは、あなたの例のように、それらの寿命が重ならない場合でも、おそらく各変数を独自のスロットに配置します。temp1temp2

興味がある場合は、gcc -O1またはで異なる結果が得られる可能性がありますgcc -O2

于 2009-03-21T23:23:57.630 に答える
4

宣言された順序に関係なく、どのアドレススタックオブジェクトが受信されるかは保証されません。

コンパイラーは、関数の結果に影響を与えない限り、スタック変数の作成と期間を喜んで並べ替えることができます。

于 2009-03-21T23:23:21.733 に答える
4

C標準は、ブロックで定義された変数のスコープと存続期間について話しているだけだと思います。変数がスタックとどのように相互作用するか、またはスタックが存在するかどうかについては、何の約束もしません。

于 2009-03-21T23:27:11.880 に答える
2

私はそれについて何かを読んだことを覚えています。私が今持っているのは、このあいまいなリンクだけです。

みんなに知らせるために(そしてアーカイブのために)、私たちのカーネル拡張がGCCの既知の制限にぶつかっているようです。要約すると、非常にポータブルで非常に軽量なライブラリに関数があります。これは、何らかの理由で、Darwin上またはDarwin用にコンパイルされたときに1600バイト以上のスタックでコンパイルされます。試したコンパイラオプションや使用した最適化レベルに関係なく、スタックは、かなり再現性のある(ただし頻繁ではない)状況で1400の「マシンチェック」パニック以上でした。

Webで多くの検索を行い、i386アセンブリを学び、アセンブリがはるかに得意な人と話をした後、GCCが恐ろしいスタック割り当てを持っていることでいくらか悪名高いことを学びました。[...]

どうやらこれはgccの汚い小さな秘密ですが、一部の人にとってはそれほど秘密ではありません。LinusTorvaldsは、gccスタックの割り当てについてさまざまなリストで何度か不満を述べています(「gccスタックの使用法」についてはlkml.orgを検索してください)。何を検索すればよいかがわかったら、gccのスタック変数の標準以下の割り当てについて多くの理解がありました。特に、異なるスコープの変数にスタックスペースを再利用することはできません。

そうは言っても、私のLinuxバージョンgccはスタックスペースを適切に再利用しているので、両方の変数で同じアドレスを取得します。C標準がそれについて何を言っているかはわかりませんが、厳密なスコープの適用は、C ++でのコードの正確性(スコープの最後での破棄による)にのみ重要であり、Cでは重要ではありません。

于 2009-03-21T23:28:41.127 に答える
1

変数をスタックに配置する方法を設定する標準はありません。コンパイラで何が起こるかは、はるかに複雑です。あなたのコードでは、コンパイラは変数ab.

コンパイラーの多くの段階で、コードはSSA 形式に変換される場合があり、すべてのスタック変数はこの形式でアドレスと意味を失います (デバッガーにとってさらに困難になる場合もあります)。

2 個または 20 個の変数を割り当てる時間が一定であるという意味で、スタック スペースは非常に安価です。また、スタック スペースはほとんどの関数呼び出しで非常に動的です。これは、いくつかの関数 (より近い関数main()やスレッド エントリ関数、長寿命のイベント ループなど) を除いて、それらの関数はすぐに完了する傾向があるためです。だから、あなたはそれらを気にしないでください。

于 2009-03-22T01:48:53.037 に答える
0

これは、コンパイラとその構成方法に完全に依存します。

于 2009-03-21T23:20:16.390 に答える