auto int hogehoge; extern int fugafuga; register int foo; static int bar;
記憶クラスは4種類あるが,この中でstaticはローカル変数とグローバル変数では, 動作が異なる.したがって,5種類の動作があると考える.それぞれの動作について,次 節以降に説明する.
auto int hogehoge;
自動変数は,それが宣言されている関数が呼び出されたときに記憶領域--メモリー--
が確保されて,関数での処理が終了したら廃棄される.例えば,リスト1のよう
に関数hoge()を3回呼び出すプログラムの動作を考える.関数hoge()の中の変
数aは自動変数である.ゆえに,関数hoge()が呼び出される毎に記憶領域
aが初期化されて作成され,その関数の動作が終了する毎に廃棄が実行される.
自動的に記憶領域の処理を行われるので,「自動変数(auto)」と呼ばれる.
1 #include <stdio.h> 2 3 int hoge(void); 4 5 //=========================================================== 6 // メイン関数 7 //=========================================================== 8 int main(void) 9 { 10 int i, foo; 11 12 for(i=1; i<=3; i++){ 13 foo = hoge(); 14 printf("%d\tfoo=%d\n", i, foo); 15 } 16 17 return 0; 18 } 19 20 //=========================================================== 21 // 自動変数を使ったユーザー定義関数 hoge 22 //=========================================================== 23 int hoge(void) 24 { 25 int a=0; // 自動変数 auto int a=0 もOK 26 27 a++; // a = a+1 と同じ 28 29 return a; 30 }
このプログラムの実行結果は,以下のようになる.図2に関数呼出と 変数aの変化を示す.関数hoge()内の自動変数aは関数が呼び出された時 に作成され,関数での処理が終わった時点で消滅する.したがって,以下の結果が得られ るのである.
1 foo=1 2 foo=1 3 foo=1
static int hogehoge;
グローバル変数でも,変数の値を保存することができる.しかし,グローバル変数は他の関数か らもアクセスできるので,思わぬことで値が変更されることがある.したがって,変数の 値を保存する必要があるが,他の関数がそれを使わない場合,静的変数を使う.
静的変数を使ったプログラムをリスト2に示す.このプログラムの25行
目のみ,リスト1と異なる.すなわち, 関数hoge()の変数aが
静的変数になっている.
1 #include <stdio.h> 2 3 int hoge(void); 4 5 //=========================================================== 6 // メイン関数 7 //=========================================================== 8 int main(void) 9 { 10 int i, foo; 11 12 for(i=1; i<=3; i++){ 13 foo = hoge(); 14 printf("%d\tfoo=%d\n", i, foo); 15 } 16 17 return 0; 18 } 19 20 //=========================================================== 21 // 静的変数を使ったユーザー定義関数 hoge 22 //=========================================================== 23 int hoge(void) 24 { 25 static int a=0; // 静的変数 26 27 a++; // a = a+1 と同じ 28 29 return a; 30 }
このプログラムの実行結果は,以下のようになる.図3に1回目関数呼出と 変数aの変化を示す.関数hoge()内の静的変数aはプログラム実行に先立っ て--メイン関数の実行よりも前に--静的変数aは作成され,初期化(a=0)が行 われる.そして,プログラムが動作している間,その変数は保存される.したがって,以下の結果が得られ るのである.
1 foo=1 2 foo=2 3 foo=3
1 #include <stdio.h> 2 3 extern int foo; // どこかで宣言されているグローバル変数 4 5 int hoge(void); // プロトタイプ宣言 6 7 //=========================================================== 8 // メイン関数 9 //=========================================================== 10 int main(void) 11 { 12 int i; 13 14 for(i=1; i<=3; i++){ 15 hoge(); 16 printf("%d\tfoo=%d\n", i, foo); 17 } 18 19 return 0; 20 }
1 #include <stdio.h> 2 3 int foo=0; // グローバルな自動変数 4 5 //=========================================================== 6 // グローバルな自動変数の値を変えるユーザー定義関数 hoge 7 //=========================================================== 8 void hoge(void) 9 { 10 11 foo++; // foo = foo+1 と同じ 12 13 }
複数のソースファイルから,ひとつの実行ファイルを作成する場合,コンパイルは次のよ うにする.
gcc -o jikkou file1.c file2.c
関数hoge()中のaはfile1.cとfile2.cで使えるグローバル変数なので,次の実 行結果が得られることが理解できるであろう.
1 foo=1 2 foo=2 3 foo=3
これを解決するには,A君のfile1.cでは,
static int gvalue;
int gvalue; extern int gvalue;
グローバル変数を静的に宣言した例をリスト6の3行目に示す.
この変数fooとリスト5の3行目のfooは名前が同一で
も全く異なるものである.リストリスト5と
6からひとつの実行ファイルを作成しても,2つのfooが保
存する内容は別物である.
1 #include <stdio.h> 2 3 static int foo=5; // 静的なグローバル変数 4 5 int hoge(void); // プロトタイプ宣言 6 7 //=========================================================== 8 // メイン関数 9 //=========================================================== 10 int main(void) 11 { 12 int i; 13 14 for(i=1; i<=3; i++){ 15 hoge(); 16 printf("%d\tfoo=%d\n", i, foo); 17 } 18 19 return 0; 20 }
1 #include <stdio.h> 2 3 static int foo=0; // グローバルな静的変数 4 5 //=========================================================== 6 // グローバルな自動変数の値を変えるユーザー定義関数 hoge 7 //=========================================================== 8 void hoge(void) 9 { 10 11 foo++; // foo = foo+1 と同じ 12 13 }
静的なグローバル変数が理解できたならば,次の実行結果は納得できるであろう.リスト 5の16行目のfooは,file1.cのグローバル変数のfoo のことである.
1 foo=5 2 foo=5 3 foo=5
register int rgsval;
一般に,アクセスの多い変数をレジスターに割り付ける.例えば,ループ文の制御変数で ある.リスト7の例では,制御変数のiとj,計算結果を格 納する変数kにレジスター変数を割り当てている.
1 #include <stdio.h> 2 3 //=========================================================== 4 // メイン関数 5 //=========================================================== 6 int main(void) 7 { 8 register int i, j, k=0; 9 10 for(i=1; i<=10000; i++){ 11 for(j=1; j<=10000; j++){ 12 k=i+j; 13 } 14 } 15 16 return 0; 17 }
次のようにすると,プログラムの実行時間が分かる.ただし,リスト 7をコンパイルした実行ファイルをtest_regとする.
time ./test_reg
実行結果は,次のようになる.最初のrealが実際にプログラムの実行に要した時間である.
real 0m0.110s user 0m0.108s sys 0m0.000s
レジスター変数を使わない場合,realの時間は0.227秒であった.レジスター変数を使う と倍の速度で計算できることが分かる.