定義された変数がプログラムのどの範囲で使うことが出来るかを示すのが通用範囲です。スコープともいいます。この通用範囲によって変数を分類すると「ローカル変数」と「グローバル変数」に分けられます。
ローカル変数
ローカル(局所)な部分で使う変数。関数の中で定義され、その関数の中でのみ参照できる。
グローバル変数
グローバル(大域)な部分で使う変数。関数の外で定義され、どこからでも参照できる。
[ 例 ] ローカル変数とグローバル変数の例
ex8-1.c
/* --< グローバル変数 >-- */
int count;
/* ---< プロトタイプ宣言 >--- */
void print_max (int val1, int val2, int val3);
void main (void)
{
count++;
/* countはどこからでも参照できる */
print_max (10,3,50);
count++;
print_max (23,6,17);
}
void print_max (int val1,int val2,int val3)
{
int max;
/* max は print_max()内だけで
使えるローカル変数 */
if (val1 > val2) {
max = val1;
} else {
max = val2;
}
if (val3 > max) {
max = val3;
}
/* countはどこからでも参照できる */
printf ("count = %d max = %d\n", count, max);
}
count はグローバル変数なので、main ( ) でも print_max ( ) でも参照できます。一方、max は print_max ( ) 内でだけ使えるローカル変数なので、main ( ) 内では参照できません。
記憶クラスの宣言は変数の宣言をするときにデータ型と同時に宣言をします。
今までの変数宣言は型宣言だけで記憶クラスの宣言を省略していたのです。このように記憶クラスの宣言は省略することもできます。
さて、宣言に使う記憶クラスは次の4通りです。
○自動変数 auto
○レジスタ変数 register
○外部変数参照 extern
○静的変数 static
それではそれぞれがどのような働きなのかを見てみましょう。
A.自動変数 auto
自動変数は
関数内部で宣言されその関数内でのみ有効な変数(=ローカル変数)です。
確保される領域はスタック領域またはレジスタ上(=動的領域)です。
関数内の変数宣言時に記憶クラスを省略するとこの自動変数と見なされます。通常は auto は省略します。
| int func (void) { auto int sun; auto char buf [10] ; auto long size; ・・・ } | = | int func (void) { int sun; char buf [10] ; long size; ・・・ } |
B.レジスタ変数 register
レジスタ変数は
自動変数をレジスタに割り当てたい場合に使います。レジスタに変数を確保するとプログラムの実行速度が高められるので関数内で何度も使われる変数に用いると効果的です。
レジスタ変数に指定できるデータ型は限定されています。可能なデータ型は、
char型、
int型、ポインタ(今後別の章で説明されます)です。
register int sum ; | /* int型の変数をレジスタ変数で宣言 */ |
float avg ; | /* float型はレジスタ変数に指定できない */ |
レジスタの数はとても少ないのレジスタ変数として宣言できる変数の数も制限されてしまいます。このレジスタの数を超えて宣言された場合は自動変数として扱われます。
レジスタはCPUの内部にあるのでCPUの特徴を十分理解しないと意味がありません。例えば、レジスタが4つしかないの一度に10個ものレジスタ変数を宣言しても意味がないと言うことです。
しかし、現在使われているほとんどの
コンパイラは、プログラムの実行速度が速くなるように変数の割り当てを最適化してくれます。つまり、プログラマがレジスタ変数を意識して使う必要性はほとんどありません。
特別な理由があって最適化しない場合は、次のように宣言するとコンパイラは最適化処理は行いません。
volatile int dat;