4.記憶クラス

ご注意:C++11利用の場合
C++11ではこれまでのCやC++03と違いautoが型推論のキーワードとして再定義されています。
よって以下のコードそのままではC++11上で正しくコンパイルできません。
C言語のautoキーワードは省略可能ですのでC++11上でコンパイルする場合はこの章のautoは全て削除して実行して下さい。

なおC++11の型推論についてはWikiPediaのC+11#型推論を参照下さい
4-1. 自動・静的
4-2. レジスタ
4-3. 外部結合
4-4. スコープ

4-1. 自動・静的

◆記憶クラス

久々、変数の宣言に戻ります。すでに配列をやったのでこれからは変数と配列をまとめてオブジェクトと呼びます。後に出てくる構造体などもオブジェクトに含まれます。

さて、いままでの変数の宣言の仕方について、

[修飾子] [データ型] [オブジェクト名] = [初期化値] ;

または、

[修飾子] [データ型] [オブジェクト1], [オブジェクト2] … ;

という形でした。修飾子とはunsignedなどの型を拡張する接頭語です。

…で、この修飾子についてまだ、やってないものがあります。

上のようにオブジェクトを宣言するとメモリにそのオブジェクト用の領域を確保します。

そして、プログラムが終了するとそれらの領域はすべて開放されてしまいます。

しかし、プログラム中でほんの一部分でしか使わないオブジェクトが多ければメモリは領域を確保して使わない時間が長くて無駄になります。(ほかのプログラムにとって迷惑)

ということで、使用頻度の低いオブジェクトや(特に記録の必要のないもの)は必要時にだけメモリを確保すればいいことになります。

これらのメモリの領域確保の方法を記憶クラスで設定します。

記憶クラスには次のようなものがあります。

自動(auto)
静的(static)
レジスタ(register)
外部(extern)

宣言するときは修飾子よりも前につけます。

auto unsigned int a;
static const int b;
register volatile int c;
extern signed long int d;

という感じです。

◇自動・静的

まずは、自動記憶域期間(auto)

通常、関数の中で記憶クラスを省略して宣言するとautoになります。

この記憶クラスはある関数中で宣言されたときにオブジェクトの領域をメモリに確保し、その関数の終了と同時にメモリから開放されます。
なお、初期化を忘れたときの値は不定です。

void fn()
{
auto int i;
i = 3;
}

1.ある関数 fn() の実行
2.auto int i; によって整数型変数iがメモリに確保される(図1)
3.i = 3; によってiの初期化(3を代入:図2)
4.関数fn()の終了と同時に変数iを開放(図3)

fig4-1

autoの場合この繰り返しでfn()が使用されるたびに1~4の処理をします。
なお変数iの値ですが、fn()の終了と同時に消えてしまいます。

次に静的記憶域期間(static)です。

こちらは宣言されている場所にかかわらずプログラムの開始直前にメモリを確保し初期化します。初期化を忘れた場合値は0になります。
また、確保された領域はプログラムが終了するまで保持されるので関数の終了時に値が消えることがありません。2回目以降関数内のstaticオブジェクトを利用するときは前回の値から始まります。

void fn()
{
    static int i;
    i = 3;
}

1.プログラムの開始と同時に確保&初期化(図4)
  ただし初期化はこの1回限りになる。
2.i = 3; によって i に3を代入(図5)
3.fn()の終了、値は保持(図6)
fig4-2

自動記憶域期間と静的記憶域期間の比較ができるプログラムを示します。

#include<stdio.h>

void fn();

main()
{
    int i;
    for(i=0;i<10;i++)fn();
}

void fn()
{
    auto   int a=0;
    static int b=0;

    a++; b++;

    printf("a=%d, b=%d\n",a,b);
}

結果:
a=1, b=1
a=1, b=2
a=1, b=3
a=1, b=4
a=1, b=5
a=1, b=6
a=1, b=7
a=1, b=8
a=1, b=9
a=1, b=10

このように自動変数のaはfn()が呼び出されるたびに0に初期化されfn()の終了とともに値を失うので毎回1になります。

それに引き換え静的変数bは最初0で初期化されますが、初期化はこれっきりでfn()が終了しても値は保持しています。よって2回目以降fn()が呼び出されたときは前回の値を保持しているのでそれに1を足して表示していきます。

※今回のプログラムについて

main以外の関数を使って呼びだしをしていますがプログラミングについての解説はここではいたしません。とりあえず、結果の表示より自動と静的の違いを比較してご理解願いたいと思います。