局所変数と広域変数
自動変数と静的変数──関数内で消滅する変数とプログラムの実行中存在し続ける変数──は、変数が『いつ生成されて、いつ消滅するのか?』を規定するものです。これとは別に、変数には局所変数と広域変数という分類があります。
変数を参照できる範囲
局所変数は「ローカル変数」とも呼ばれ、『一定の処理範囲内だけで参照できる変数』です。広域変数は「グローバル変数」とも呼ばれ、『複数の処理範囲をまたいで参照できる変数』です。
局所変数は、関数の中で宣言された変数です。関数の中で宣言された変数は、自動変数であっても静的変数であっても、宣言された関数内からのみその値を参照でき、他の関数から参照することはできません。
一方広域変数は『関数の外』で宣言され、同じソースファイル中のすべての関数から値を参照できます。
広域変数は関数の外で宣言されるため、一般には宣言と同時に初期化します。また、main関数の中で他の関数を呼び出す前に初期化することもできます。
プログラムで試す
広域変数と局所変数の違いをプログラムで試してみましょう。リスト2では、int型の変数aが広域変数で、main関数より先に(すべての関数の外側で)宣言され、0で初期化されています。
main関数では関数countを10回呼び出しています。count関数の中ではint型の局所変数bを宣言し、0で初期化しています。
その後、先のリスト1と同じく2つの変数の値を表示し、続いて両者の値を1増加しています。
実行すると画面2のようになります。count関数内で宣言されている局所変数bは呼び出されるたびに初期化されるため、常に0となっています。一方、広域変数aはcount関数の外で宣言されていますがその値を参照できるため、count関数で値を表示したりインクリメントしたりできます。
リスト2:グローバル変数とローカル変数の働きを確かめる(ex3402.c)
#include <stdio.h>
int a = 0; /* 広域変数の宣言と初期化 */
void count(void); /* 関数の宣言 */
int main(void)
{
int i;
/* countを10回呼び出す */
for (i = 0; i < 10; i++) {
printf("%d : ", i+1); /* 呼び出し回数 */
count();
}
return (0);
}
/* 呼び出された回数を表示 */
void count(void)
{
int b = 0; /* 局所変数の宣言と初期化 */
printf("global -- %d / local -- %d\n", a, b);
a++; /* 広域変数を1加算 */
b++; /* 局所変数を1加算 */
}
画面2:ex3402.exeの実行結果
C:\CLANG\EXE>ex3402
1 : global -- 0 / local -- 0
2 : global -- 1 / local -- 0
3 : global -- 2 / local -- 0
4 : global -- 3 / local -- 0
5 : global -- 4 / local -- 0
6 : global -- 5 / local -- 0
7 : global -- 6 / local -- 0
8 : global -- 7 / local -- 0
9 : global -- 8 / local -- 0
10 : global -- 9 / local -- 0
C:\CLANG\EXE>
このように広域変数は、ソースファイル内の関数から自在に参照できます。しかし、たとえばmain関数の中で次のようにしてcount関数内で宣言された変数bを参照することはできません。
printf("b = %d /", b);
コンパイル時に「'b'という識別子が定義されていない」というエラーが発生します。変数bは、main関数とは別の処理単位である関数count内で宣言された変数だからです。
広域変数の多用はNG!
広域変数はどこからでも参照できるため、関数内で消滅する局所変数より便利な気がします。そのため、プログラムで必要なデータをすべて広域変数としてしまう人もいるようです。
しかし、広域変数は「どの処理(関数)がその値を書き換えたのか」が見通しにくくなるため、プログラムの構造を把握することが困難になり、デバッグや仕様変更の際に苦労します。
Cでは、関数同士のデータのやり取りは引数と戻り値で行い、広域変数の使用は極力控える――というのがセオリーです。
*
変数には、
宣言された処理単位(関数)内でのみ存在する自動変数
処理を終えても存在して値を保持し続ける静的変数
の2種類があります。これは、変数の『通用期間』に関する違いです。
さらに
宣言された処理単位(関数)内でのみ参照できる局所変数
処理単位の外からでも参照できる広域変数
の2種類があります。これは、変数の『通用範囲』に関する違いです。
|
|
|