3

2番目の閉じ中括弧の後、 。を介したb間接参照を介してのみアクセスできますa

int main() {
    int *a;
    {
        int b = 42;
        a = &b;
    }
    printf("%d", *a); // UB?
    return 0;
}

bスコープがなくなったので、これはUBですか?すでに返された関数から非静的ローカル変数へのポインターを逆参照するのはUBであることを私は知っていますが、この場合、すべてが同じ関数内にあります。

これはC++のUBですが、Cについてはよくわかりません。

4

2 に答える 2

5

bはまだ別のネストされたスコープ内にあり、bアクセスするまでに終了して破棄されています。したがって、これは未定義の動作です。同じ機能内にあるものはすべて重要ではありません。

可変ライフタイムの目的で、「返された関数」をネストされたスコープと考えることができます。その逆も可能です。

于 2013-01-02T02:56:18.443 に答える
5

はい、寿命に達した変数にアクセスするのは未定義の動作です。ここでは、スコープと保存期間が微妙に異なります。スコープは「変数識別子はいつ表示されますか?」保存期間は「変数自体はいつ存在しますか?」です。

次のような範囲内で永続的なものを持つことができます。

int main (void) {
    int spoon = 42;
    // spoon is both in scope and enduring here
    return 0;
}

または範囲外ですが、永続的です:

int main (void) {
    int *pSpoon;
    {
        static int spoon = 42;
        pSpoon = &spoon;
    }
    // spoon is out of scope but enduring here (use *pSpoon to get to it)
    return 0;
}

また、次のように、範囲外で永続的でない変数を使用することもできます。

int main (void) {
    // spoon is neither in scope nor enduring here ("there is no spoon")
    return 0;
}

実際、あなたが持つことができない唯一のものは、スコープの変数ですが、永続的ではありません。バッキングストレージのない変数を許可することはほとんど意味がないため、識別子はストレージに関連付けられています。

ここではポインターについて話していません。これは、余分なレベルの間接参照です。スコープ内のポインター変数には、ポインターが指すものが終了したか、まだ開始されていない場合でも、ポインター値自体のストレージが常にあります。

未定義の動作が特定の状況で機能する可能性があるという事実は、動作を定義するものではありません。実際、未定義の動作の最も厄介な機能の1つであり、機能することがあります。そうしないと、検出がはるかに簡単になります。

この特定のケースでは、b可変ストレージ期間は内側の閉じ中括弧で終了するため、その時点以降にアクセスしようとするのは賢明ではありません。


標準の制御部分は次のとおりですc11 6.2.4 Storage duration of objects(不要なビットを削除するために少し言い換えます):

オブジェクトには、その存続期間を決定する保存期間があります。保存期間には、静的、スレッド、自動、および割り当ての4つがあります。

リンケージなしで、ストレージクラス指定子staticなしで識別子が宣言されているオブジェクトには、自動ストレージ期間があります。

このようなオブジェクトの場合、その存続期間は、関連付けられているブロックへのエントリから、そのブロックの実行が何らかの方法で終了するまで延長されます。

于 2013-01-02T03:00:05.183 に答える