大域変数とは
大域変数(たいいきへんすう)とは、プログラムのどこからでも読み書きができる変数のことです。「グローバル変数」とも呼ばれます。これに対して、特定の関数や処理ブロックの内部だけでしか使えない変数を「局所変数(ローカル変数)」と呼びます。大域変数はプログラム全体の共通データ(アプリの設定やログイン中のユーザー情報など)を管理するのに便利ですが、どこからでも書き換えられてしまうため、意図しない場所で値が変更され、プログラムに予期せぬバグを引き起こす原因になりやすいというデメリットがあります。そのため、プログラム設計の際はできるだけ大域変数の使用を避け、局所変数を使うことが推奨されます。
具体例
ゲーム内でゲーム全体の難易度設定やプレイヤーの残りライフ数を管理する場面です。以下のプログラムのように、関数の外で定義された変数は大域変数となり、どの関数からでも値を変更したり参照したりできます。
let maxLife = 3; // 大域変数(グローバル変数)
function damage() {
maxLife = maxLife - 1; // 関数の中から大域変数を書き換える
}
damage();
console.log(maxLife); // 結果は「2」になる
もう少し詳しく
大域変数(グローバル変数)は、プログラムの開始時から終了時までずっとメモリ上に存在し続け、プログラムを構成するすべての関数やファイルから自由に読み書き(参照と代入)ができるという強力な特性を持った変数です。これは、システム全体で共有すべき設定情報(データベースへの接続情報や、環境設定パラメータなど)を保持するためには非常に便利で手軽な方法です。
しかし、現代のソフトウェア開発においては、「大域変数の使用は極力避けるべき(あるいは禁止するべき)」というのが共通のベストプラクティスとなっています。その最大の理由は、プログラムの「保守性」と「安全性の低下」です。
プログラムが大規模になり、数百、数千の関数が存在するようになると、ある大域変数の値が「いつ、どこで、どの関数によって書き換えられたのか」を追跡することが極めて困難になります。例えば、ある関数Aが計算のために大域変数の値を期待して処理を行っている途中で、全く無関係に見える関数Bが誤ってその大域変数を書き換えてしまった場合、関数Aは原因不明のバグを引き起こします。これを「副作用」と呼びます。開発チームの別の人が書いたコードによって、自分の書いたコードが予期せず壊れてしまうリスクが常に付きまといます。
また、大域変数に依存している関数は、その大域変数が存在しない別のプログラムにコピーして再利用(部品化)することが難しくなります。そのため、データを関数に渡したい場合は、大域変数を使うのではなく、関数の「引数(ひきすう)」として明示的にデータを渡し、処理結果を「戻り値」として受け取るという設計(局所変数と引数を用いた設計)にすることが、バグの少ない堅牢なプログラムを作るための基本原則となっています。
試験でのポイント
情報処理技術者試験では、大域変数はプログラミングの知識問題として、あるいはアルゴリズム問題のコードの中に登場する形で問われます。
知識問題として頻出なのは、「局所変数(ローカル変数)」との明確な違いです。「関数の中で宣言され、その関数が終了すると同時にメモリから消滅し、使えなくなる変数はどれか」という問いに対しては局所変数を選び、「関数の外で宣言され、プログラムの実行中ずっと保持され、複数の関数から共有される変数はどれか」という問いに対しては大域変数(グローバル変数)を選ぶ、という定義の違いを正確に理解しておく必要があります。
アルゴリズム問題のトレースにおいては、大域変数が登場した場合は最大の警戒が必要です。疑似言語のコードを読む際、複数の関数が順番に呼び出される中で、大域変数の値がどのように変化していくかを余白にメモしながら追いかけなければなりません。特に、関数の中で大域変数と同じ名前の局所変数が宣言されている「名前の衝突(シャドウイング)」のケースに注意してください。この場合、その関数の中では局所変数が優先して使われ、大域変数の値は書き換わらない、という言語のルール(スコープの規則)を理解しているかを問うような、引っかけ問題が出題されることがあります。
また、オブジェクト指向プログラミングに関する問題では、大域変数の欠点を克服するための仕組みとして「カプセル化」という概念が関連して問われることがあります。データ(変数)を外部から勝手に書き換えられないように保護するという考え方は、大域変数のデメリットを理解していれば非常に納得しやすいはずです。
関連する用語
局所変数、スコープ、副作用