変数のスコープ(scope)とライフタイム(lifetime)は、Cプログラムの構造における重要な側面の一つです。スコープは、変数が名前でアクセスできるコードの部分です。ライフタイムは、変数が実際にメモリに存在する時間を定義します。
問題の背景
Cは低レベルの制御のために設計されたため、変数の宣言場所による分類(ブロック、ファイル、グローバル、静的)を通じて、スコープとライフタイムに対して柔軟ですが危険なアプローチを提供します。
問題
スコープ/ライフタイムの誤解は、古典的なバグを引き起こすことがあります:無効または既に破棄された変数にアクセスしようとした場合(use-after-free)、グローバル変数とローカル変数間の名前の衝突(シャドウ変数)、意図せずグローバル変数を変更すること。
解決策
必要なストレージタイプ(auto、static、extern)を明示的に定義し、ブロックスコープを合理的に使用し、グローバル変数の数を最小限に抑え、スタックとスタック外のライフタイムを明確に区別すること。
コード例:
int global_var; // グローバル、全ランタイム中生存 void func() { int local_var = 5; // 自動、func()内で生存 static int stat_var = 0; // 静的、呼び出しの間で生存 stat_var++; }
主な特徴:
異なるブロックに同じ名前の二つの変数を宣言した場合、どうなりますか?
内側の変数が外側の変数を隠します(シャドウ変数)。これが予期しないエラーを引き起こすことがあります。
int x = 10; ... if (1) { int x = 50; printf("%d", x); // 50を印刷、グローバルxは隠される }
関数内で定義された自動変数のライフタイムはどうなりますか?
この変数は関数の呼び出し中にのみ存在します。呼び出しを終えると、メモリは解放され、値は失われます。
静的ローカル変数は、宣言された関数の外で使用できますか?
いいえ、スコープは関数内のみに限定されます。ライフタイムはプログラムの実行中ずっとですが、外部からは見えません。
void f() { static int x = 0; } // f()の外ではアクセス不可
static vs auto)。初心者の開発者がループ内にカウンタをstaticとして作成した場合、このカウンタはイテレーションの間に値を「蓄積」しますが、毎回ゼロにリセットされることが期待されていました。
長所:
短所:
開発者はキャッシングのためにのみstaticを使用し、一時的なニーズには通常のauto変数を使用します。
長所:
短所: