関数の外側、ファイルの先頭で宣言した変数は、そのファイルのどの関数からも見えます。これがグローバル変数です。家中の誰でも触れる、廊下に置かれた共有の棚だと思ってください。
#include <stdio.h>
int total = 0; // グローバル変数(初期値を書かなければ0)
void add(int n)
{
total += n; // どこからでも触れる
}
int main(void)
{
add(3);
add(4);
printf("%d\n", total); // 7
return 0;
}引数も戻り値もなしに値を共有できるので、一見すると便利です。寿命はプログラムの開始から終了までで、初期値を書かなければ 0 に初期化されます(static 局所変数と同じ性質です)。
なぜ「便利」に見えるのか
グローバル変数を使えば、引数と戻り値をどう設計するか考えずに済みます。書くのが速い——これが最大の誘惑です。ところがプログラムが育つほど、「速く書ける」より「速く直せる」ほうが大切になります。バグの原因を探している時間は、コードを書いている時間よりずっと長いからです。
便利さの代償
しかしグローバル変数は、規模が大きくなるほど扱いにくくなります。
- どこで書き換わったか分からない。
totalがおかしい値になったとき、容疑者はファイル中のすべての関数です。スコープが広いほど捜査範囲が広がります。 - 関数が単独でテストできない。同じ引数で呼んでも、グローバルの状態次第で結果が変わります。
- 名前がぶつかる。ファイルが増えると、同じ名前の変数が別の場所で定義されて衝突します。
そこで、外に出したくないグローバルには static を付けます。
static int total = 0; // このファイルの中だけから見える局所変数に付ける static は「寿命を延ばす」意味でしたが、グローバルに付ける static は「見える範囲をこのファイルに限定する」という別の意味になります。同じキーワードで役割が2つある、Cの少しややこしい部分です。
局所変数で足りないか、まず疑う
グローバルにしたくなったら、次の順に検討してください。上から順に「見える範囲が狭い」順です。
- その関数の中だけで済む → 局所変数
- 呼び出し元とやりとりすれば済む → 引数と戻り値
- その関数だけが値を覚えていればよい → static 局所変数
- どうしても複数の関数で共有が必要 → ファイル内 static のグローバル
いちばん狭い選択肢で足りるなら、それが最善です。どうしてもグローバルを使うなら、total のような短い名前は避け、g_total のようにひと目でグローバルと分かる名前にしておくと事故が減ります。
使ってよい場面
設定値や定数のように、書き換えない共有データはグローバルでも安全です。その場合は const を付けて、書き換えを文法レベルで禁止しておきます。
const double TAX_RATE = 0.10; // 誰も書き換えられない読むだけの共有データなら、誰から見えても事故は起きません。危ないのは「みんなが書き換えられる」状態のほうだ、と覚えておくと判断しやすくなります。
まとめ: グローバル変数は「便利だが追跡しづらい」。まずは引数と戻り値でやりとりし、どうしても共有が必要なときだけ、static や const で範囲と権限を絞って使いましょう。