はい、寿命に達した変数にアクセスするのは未定義の動作です。ここでは、スコープと保存期間が微妙に異なります。スコープは「変数識別子はいつ表示されますか?」保存期間は「変数自体はいつ存在しますか?」です。
次のような範囲内で永続的なものを持つことができます。
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なしで識別子が宣言されているオブジェクトには、自動ストレージ期間があります。
このようなオブジェクトの場合、その存続期間は、関連付けられているブロックへのエントリから、そのブロックの実行が何らかの方法で終了するまで延長されます。