もう、何回もサンプルプログラムの説明などで出てきているので
ウスウス「スコープ」については気がついていると思います。
原則的に、Cでは、変数は関数内で宣言し、その関数内でしか参照する(見る)ことが
できません。大昔のBASIC(インタプリタの時代の)では変数は、どこからでも参照
する事ができました。これに慣れている人には最初のうちちょっととまどうかもしれません。
でも長いプログラムを書くときは、Cの方がずっと便利です。変数名がいろいろ登場してくると
うっかり、同じ名前の変数名を別のところで違う意味に使ってしまうことが生じます。
複数の人が、分担して一つのアプリケーションを開発しているときなどは特にそのような
問題が発生することでしょう(想像です)。
要するに、変数の宣言する位置でその変数の見える範囲(scope) が、違ってきます。例を挙げて説明します。
#include <stdio.h> void call_func(void); int x = 10; //グローバル変数,外部変数とも言う int main(void) { int x = 20; //局所変数,main関数内のみで通用 printf("局所変数x=%d\n", x); call_func(); return 0; } void call_func(void) { extern x; //この宣言は書かなくてもよい printf("外部変数x=%d\n", x); return; }
最初にグローバル変数xを宣言して、初期化しています。このxは どこからでも見ることができます。
次に、main関数内で同じ名前のxという局所変数を宣言しています。
参考書によっては、局所変数を内部変数と同義に扱っている
ものもありますが、
普通は局所変数と内部変数では
意味が異なります。
この関数内でxを参照するときは局所変数のxが優先されます。
次に、call_func関数で、外部変数のxを宣言しています。
(extern x;)これは、省略されることの方が多いです。
外部変数ですから、いきなり参照してかまいません。
実行結果は左の通りです。
変数は、プログラムが実行されている間中ずっと生き続けている 訳ではありません。寿命があります。これを難しい言葉で 「記憶期間(storage duration)」などといいます。これは、 すでに説明したスコープとも密接に関係しています。 こういった、スコープや記憶期間の状態を 「記憶クラス(storage class)」と言います。 これは、変数のみならず関数にも当てはまります。
記憶クラスには次の4つがあります。最後のは、ほとんど使いません。 (筆者は。他の人は知りません。)
auto(自動変数)
static(静的変数)
extern(外部変数)
register(レジスタ変数)
もっともよく使うのが自動変数です。 関数の内部で宣言します。当然スコープはその関数内のみです。 また、その変数が呼び出されるごとに変数は初期化されます。 従って、寿命はその関数が呼び出されているときのみとなります。 本当は、auto int x; などと宣言するのですがautoが 省略されるのが普通です。
性的変態いや、静的変数を関数の外部で宣言されるか内部で宣言されるか によってわけて説明します。
(a)関数の内部でstatic宣言
当然宣言された関数の内部でしか参照できません。
しかし、プログラムの最初から、終了まで値が保持されます。
(死なない)自動変数ですと、初期化しないとその変数に
何が入っているかわかりませんが(不定)、静的変数ですと
初期化されていないときは0が入っています。
(b)関数の外部でstatic宣言
そのソース・ファイル内で参照可能となります。
初期化されていないときは0が入っています。
(内部変数)値はプログラムが終わるまで記憶されています。
しかし、その外部宣言が行われるよりも前に書いてある
関数では参照できません。
と、いうプログラムでは外部的にstaticな変数xは、 func1()内では参照できますがmain関数からは 参照できません。もちろんプログラムの一番最初に書けば main関数からも参照できます。その例です main() { ・・・・ func1(); ・・・・ } static int x = 1; void func1(void) { ・・・ }
次に外部変数です。これも関数外で宣言します。 寿命はプログラムが終了するまで続きます。 そのソース・ファイルのみでなく他のファイルからも 参照できます。
どうですか、わかりましたか。//source1.c int x=1; main() { ・・・//当然xを参照できる } func1() { ・・・//ここでも参照できる } //ここから別のファイルsource2.c func2() { extern x;//ここで宣言するとfunc2のみで //source1.cのxが参照できる ・・・ } func3() //この関数からはxを参照できない { //source2.cの一番最初でextern x; ・・・//とすればこの関数からも参照できる }
次にレジスタ変数ですが他の変数と異なり
CPU内部のレジスタを記憶場所とします。
普通のメモリより高速にアクセスできます。
パソコンレベルではレジスタの数は多くないので
(筆者は詳しいことは知らない)
これを頻繁に使うことはありません。また、最近の
コンパイラは勝手に、必要な変数をレジスタ変数に
してくれるので下手にこんな宣言をしない方が無難です。
従って覚える必要はありません。
記憶クラスは、変数だけに適応されるものではありません。
関数についても内部関数、外部関数といった概念があります。
今回は、いろいろ面倒なことをやったので関数についての
記憶クラスについては、別な章で解説します。
それと、念のために書いておきますがこの章で出てきた
「クラス」とはC++の「クラス」とは何の関係もありません。
Update Nov/23/1996 By Y.Kumei