変数が値を記憶するためのメモリ領域を確保している期間をその変数の「寿命」(lifetime)と言います。変数の寿命は,プログラム内でメモリの割り当て(allocate)をしない限り,次の2つとなります。[C99, 6.2.4]
■記憶域期間(Storage Duration)
リンケージを持つか,或いは static
を付した場合。寿命はプログラムの実行全体。
リンケージを持たず,かつ static
を付さない場合。寿命はそのブロック内。
今後は,自動記憶域期間をもつ変数を「自動変数」,静的記憶域期間をもつ変数を「静的変数」と略称することとします。
初期化は,記憶域期間によってルールが異なります。
明示的に初期化されない限り,値は不定。[C99, 6.7.8, 10] 初期化はそのブロックの実行毎に行われる。[C99, 6.2.4, 5]
明示的に初期化されない場合,0
と初期化される。[C99, 6.7.8, 10] 初期化はプログラムのスタート前に一度のみ行われる。[C99, 6.2.4, 3]
/* Example 16.4 */ #include <stdio.h> int n; static double r = 3.14; int main(void) { printf("n = %d\n", n); printf("r = %f\n", r); { extern double r; int n = 2; static long l = 1234567890L; printf("n = %d\n", n); printf("r = %f\n", r); printf("l = %ld\n", l); } printf("n = %d\n", n); printf("r = %f\n", r); printf("l = %ld\n", l); /* コンパイル・エラー */ return 0; }
最初の変数 n
は外部結合をもつので静的変数です。上の場合 0
に初期化されます。変数 r
は内部結合をもつので静的変数となり,3.14
と初期化されます。次に main
関数の中にあるブロック { }
内ですが,
extern double r;
の変数 r
は,6行目で宣言した内部結合をもつ静的変数 r
と同じリンケージ(内部結合)を持つこととなります。したがって,ブロック・スコープを持ちながらリンケージも持つので初期化はできません。初期化は,その外部定義(6行目)に従います。一方,
int n = 2;
は,5行目で 0
と初期化された外部結合をもつ変数 n
を隠す(hide)ため,これとは別個のプロック・スコープをもつ int
型自動変数 n
を定義することとなり,2
と初期化されます。また,
static long l = 1234567890L;
は,long
型変数 l
を 1234567890
と初期化しています。この変数は,リンケージは持ちません。しかし,static
を付しているので静的変数です。静的変数ですがブロック・スコープを持つので,その有効範囲外では使用できません。ソース内の
printf("l = %ld\n", l); /* コンパイル・エラー */
部分を削除せずにコンパイルすると,`l' undeclared
といった具合に「宣言されていません」というエラーが出ます。エラーが出ないように修正したものをコンパイルし,実行ファイルを実行すると,次の出力を得ます。
n = 0 r = 3.140000 n = 2 r = 3.140000 l = 1234567890 n = 0 r = 3.140000
上の変数 l
のようなプロック・スコープをもつ静的変数をその有効範囲外で参照するにはどうすれば良いのか,あるいは,そもそもそのような変数をいつ使用するのか,といった疑問を持ったことでしょう。次はその例です。
/* Example 16.5 */ #include <stdio.h> char *f (void); int main (void) { char *y; y = f(); printf("%s [%p]\n", y, y); return 0; } char *f (void) { static char str[8] = "testing"; char *x = str; return x; }
これは malloc
でメモリを割り当てる Example 10.17
を static
を使って静的に割り当てたケースです。ポインタを渡せば,有効範囲外でも参照することができます。
仕様書(C99)理解度 ○×クイズ
1. static
を付せば,結合をもつ。
2. static
を付せば,内部結合をもつ。
3. extern
を付せば,結合をもつ。
4. extern
を付せば,外部結合をもつ。
5. 変数の寿命を静的記憶域期間にするには,static
を付さなければならない。
6. 外部宣言された変数の寿命は,静的記憶域期間となる。
答え:1 × 2 × 3 ○ 4 × 5 × 6 ○
* C99 を作成していた人達によると,スコープ,リンケージ,記憶域期間は,伝統的に混乱していた領域であったという。(ISO/IEC JTC1/SC22/WG14, A draft rationale for the C99 standard (N897), p.30.)