C言語では変数のストレージクラスがデータの格納場所、利用可能な期間、およびどのコードの範囲がそれらにアクセス可能であるかを決定します。歴史的に、auto(ローカル変数のデフォルト)、static(呼び出し間で値を保持、状態を保存するためによく使用される)、およびextern(他の場所で定義された変数を宣言する)が導入され、変数のスコープとライフタイムを管理してきました。
問題 — 変数がどこでどれだけ生存するかを誤解すると、アクセスエラー、メモリリーク、および読みづらいコードにつながる可能性があります。たとえば、ローカル変数staticが各関数呼び出し時に再生成されると誤って期待することや、逆にauto変数が呼び出し間で値を保持すると考えること。または、static変数は関数の外からは見えないこと。
解決策 — ストレージクラス指定子を常に意識的に選択し、その結果を理解すること:
使用例:
// main.c int global_var = 42; // デフォルトでstaticストレージクラス、外部リンク void func() { static int counter = 0; // 呼び出し間で生存 auto int temp = 5; // ローカル、autoを明示的に指定する必要はない counter++; printf("call #%d ", counter); } extern int global_var;
主な特徴:
autoを書く意味は何ですか?それとも変数はデフォルトでautoではありませんか?
答え:Cの現代のバージョンでは、autoキーワードはほとんど明示的には使用されません—ローカル変数にとってはデフォルトの指定子です。一般的に、それを明示的に書くことは何の利点もありません。
関数内でstaticを使用してグローバル変数を宣言できますか?
答え:いいえ、関数内のstaticは変数をローカルにしますが、呼び出し間で状態を保存します。関数の外では見えません。
コードの例:
void foo() { static int call_count = 0; // グローバルではないが、呼び出し間で生存 call_count++; }
関数内で変数をexternとして宣言し、どこにも定義しないとどうなりますか?
答え:これはリンカエラーを引き起こします。なぜなら、存在しないグローバル変数への参照が宣言されているからです。
大規模なプロジェクトで、モジュール変数をすべてのソースファイルでexternとして宣言しましたが、定義をするのを忘れました。その結果、初心者には不明な神秘的なリンカーエラーが発生しました。
利点:
欠点:
スコープを厳密に定義しました:必要なモジュールの各static変数、グローバルなexternはヘッダファイルで宣言し、唯一の場所で定義されます。
利点:
欠点: