サイトマップ / C言語講座>出入り口>総目次>目次:入出力(1)>変数の記憶クラス
[関数を自作する]←このソース→[変数の取りうる値の範囲]
/* Cでは、変数を宣言する時、必ず、型と名前を指定します。 */
/* 今までに幾つかの変数の型について学びました。変数は、メモリ上のどこかに存在します。どこに置くかを指定するのが、記憶クラス指定子です。記憶クラスは、変数のメモリ上の位置と、存在期間を決定します。
記憶クラスには、4つあり、自動、静的、外部、レジスタがあります。
重要:変数は目的により記憶クラスを使い分ける。
自動変数のことを局所変数、外部変数のことをグローバル変数(大域変数)ともいいます。
Cは関数型の言語です。何かの処理は関数の実行に伴って行われます。自動変数は関数の中で宣言され、実行時にスタックに割り当てられます。関数から抜けると、消滅します(コンパイラによっては、レジスタに割り付けを試みるものもあります。)。スタックはメモリを一時的にしまうところで、後にしまったものほど、先に取り出されます(後入れ先出し)。レジスタはCPUが演算対象のデータや結果を一時的にしまう場所で、もし、頻繁に出てくる変数をレジスタに割り付けられれば、プログラムの実行速度が速くなります。
静的変数は、コンパイル時にメモリが割り当てられます。関数から抜けてもその値は保持され、その関数へ制御が戻って来た時に有効になります。プログラムの実行中常に存在し続けるので、静的といいます。
グローバル変数は、関数の外部で定義され、プログラム実行時に存在し続け、他の関数からもその値を読みとり書き込みすることができます。グローバル変数の使用は最小限に留めるべきです。プログラムにバグがあった時、プログラムのどの関数が値を書き換えているか、わかりづらくなるからです。
関数の中で'register'を付けて宣言すると、レジスタ変数になります。レジスタ変数は、もし可能なら、レジスタに割り付けられます。割り付けできなくても、エラーにはなりません。その場合は、スタックに割り付けられ、自動変数になります。レジスタ変数も、関数から抜けると消滅します。
自動変数、静的変数、レジスタ変数は、他の関数の中で名前が重複していても、互いに影響しません。以上を表にまとめると
記憶クラス | 記憶領域 | スコープ | 記憶クラス指定子 |
自動変数 | スタック | { } の内側 | auto( 不要 ) |
静的変数 | 静的領域 | { } の内側* | static/td> |
外部変数 | 静的領域 | 全域 | extern** |
レジスタ変数 | レジスタまたはスタック | { } の内側 | register |
* { }の外側で宣言された時は、その行以降
** 他のファイルにある時、externを付け、その変数を宣言(メモリを確保)しているファイルでは何も付けない。
変数は名前を付けなければ、使えません。C言語では、名前(識別子)は、英字または'_'(アンダースコア)で始まり、英数字または'_'が0個以上続くという決まりになっています。'_'一つまたは二つで始まる変数は、システムに密着したデータに使います。例えば、コンパイラのプログラム等で使われます。変数に名前を付ける時、外部変数は定義されている所から遠い所でも使われるので、その変数の用途を想像できるような名にすることが推奨されています。
例:timetable, itemindex, thisyear
自動変数は通用範囲が狭いので、何の変数かがすぐわかるので、タイピングの手間を省く意味でも、短くて良いとされています。
例:i, j, m, x, c
その場合でも、その変数がなんであるかを、瞬時に連想できるものが良いとされています。例えば、整数ならば、i、j、k、n、浮動小数点数ならば、x、y、z、文字ならば、cなどです。
今回のソースプログラムでは、新しい演算子が出てきます。インクリメント演算子です。下記のコードは int型の整数iの値を1増加させます。本格的にはもう少し後に学びます。
i++;
今回のソースプログラムでは、関数の中で静的変数と自動変数を宣言します。それぞれの値を表示してから1インクリメントします。自動変数は関数から抜けると破壊されます。静的変数はメモリに存在し続けます。次に関数が呼ばれた時、自動変数は新たに作られます。前回の呼び出しで、1インクリメントした効果はありません。一方、静的変数はメモリに存在し続けているので、値が1増加しています。
このソースプログラムをコンパイルすると、コンパイラによっては、下記に示す警告が出るかも知れません。
Warning: 'j' used before set
自動変数である'j'は、宣言しただけではメモリが割り付けられただけで、その値は幾つであるかわかりません。そのプログラムの別の自動変数が使っていたメモリに割り付けられたのかも知れません。宣言しただけの自動変数にはゴミの値が入っているといいます。自動変数は使う前に何らかの値を代入します。このことを、初期化するといいます。上記の警告は初期化する前に値を読み込もうとしているということです。今回は、わざわざそうしてゴミの値を見ようとしているので、この警告は無視します。
重要:自動変数には初期化が必要。
一方、静的変数は初期化の式がなくても、コンパイル時に0に初期化されます。
重要:静的変数はコンパイル時に0に初期化される。 */
#include <stdio.h> void Func(void); /* プロトタイプ宣言 */ void main(void); /* 静的変数 i と自動変数 j の値を表示する */ void Func(void) { /* i の値を読み書きできるのはこの関数の中でだけ */ /* i はずっと存在し続け、 */ static int i; /* func( ) が呼ばれる度に1増える */ auto int j; /* 自動変数は初期化しないと */ /* ゴミの値が入っている */ /* j はゴミの値が表示される */ /* 幾つになるかはわからない */ /* auto は付けなくてもよい */ /* というより、普通は付けない */ printf("i = %d j = %d\n", i, j); /* i, j の値を表示 */ i++; /* 値を1増やす */ j++; /* 値を1増やす */ } /* 関数を抜けたこの時点で、j は破壊される */ void main(void) { Func( ); /* 呼び出す度に i の値は 1 増える */ Func( ); Func( ); } |
/* この他にも、malloc( )等により、実行時にヒープ領域にメモリを確保する変数もあります。後日、扱うことになります。
コンパイラもソフトウエアです。ソフトウエアを作るソフトウエアです。では、コンパイラをどうやって作るのでしょうか。コンパイラもコンパイラで作ります。C言語のコンパイラは、BやBCPLという言語を使って作られました。最初は簡単な仕様のコンパイラでした。このコンパイラを使って、もう少し複雑なソースプログラムをコンパイルし、コンパイラを作りました。これを繰り返すことにより、現在のコンパイラができあがったのです。 */
[関数を自作する]←このソース→[変数の取りうる値の範囲]
/* (C) 2000- YFプロ. All Rights Reserved. */ 提供:C言語講座−それ自体コンパイルできる教材を使った講座です−