このページは現在制作中です
第8回 第7回へ 目次へ
2006 / Nov / 15
はじめに
 このサイトは、プログラミングが始めての方やC言語を学習されていない方を対象に、Macのプログラミングの手法の中から「 Cocoa (ココア)」と呼ばれるものを紹介しています。
 プログラムは、プログラミング言語によって書かれているということはご存知だと思います。Cocoaでは、Objective-C言語というC言語を発展させたプログラミング言語を使用しています。この「Objective-C Primer」では、Objective-C言語を理解する上で必要となるC言語の基礎を学習して、Objective-CとCocoaの入り口までご案内することを目的としています。

ご注意  このサイトに書かれているサンプルコードの実行はあなたの自己責任において行ってください。このサイトおよび私は、このサイトのサンプルコードの実行によって発生するいかなる損害にも責任がなく保証もいたしません。
2006 / Nov / 15
グローバル変数とextern記憶クラス指定子
 ローカル変数は局所変数とも呼ばれ、グローバル変数は大域変数とも呼ばれています。

 ではmain.mを次のようにコーディングしてください。
main.m

#import <Foundation/Foundation.h>

int globalInt = 10;     // ここがグローバル変数です
int argc      = 10;     // ここもグローバル変数です

void funcA();           // funcA関数のプロトタイプです
void funcB();           // funcB関数のプロトタイプです

int main(int argc, char * argv[]) {
    NSLog(@"\n globalInt is %2d", globalInt);
    NSLog(@"\n argc      is %2d", argc);
    argc = 55;
    NSLog(@"\n argc      is %2d", argc);
    funcA();
    funcB();

    return 0;
}

void funcA() {
    int globalInt = 50; // globalIntというローカル変数を定義しています

    NSLog(@"\n argc      is %2d", argc);
    argc += 10;         // += は複合代入演算子です
    NSLog(@"\n argc      is %2d", argc);
    NSLog(@"\n globalInt is %2d", globalInt);
    globalInt += 30;    // += は複合代入演算子です
    NSLog(@"\n globalInt is %2d", globalInt);
}

void funcB() {
    NSLog(@"\n globalInt is %2d", globalInt);
    globalInt += 20;    // += は複合代入演算子です
    NSLog(@"\n globalInt is %2d", globalInt);
}

2006 / Nov / 3 更新

main.m ファイルの冒頭部分で
 空白行も入れて3行目と4行目でグローバル変数を定義(確保)し、10という整数値で初期化しています。
グローバル変数はこのようにすべての関数の外側で定義され、すべての関数から使う事ができます。グローバル変数は上記のサンプル・コードのようにファイルの冒頭部分で定義します。
 一方、ローカル変数は関数の中で定義され、その関数の中でしか使う事ができません。同じ名前のグローバル変数が存在する場合はローカル変数が優先されます。その場合は、その関数内からは、その同名のグローバル変数を使う事はできません。
 ローカル変数は、あくまでも定義された関数の中だけが有効な範囲なので、複数の関数内で同名のローカル変数が定義されていてもまったく問題はありません。それぞれの関数内の同名のローカル変数はまったく違うものとして扱われます。このような有効範囲のことをスコープ(scope)と呼びます。

2006 / Nov / 10 更新

 赤字で表示されている「ローカル変数」というところを間違って「グローバル変数」と記述していました。すみません。

2006 / Nov / 11 訂正

 なお、グローバル変数はプログラムが起動する時にメモリ上に確保されて、プログラムが終了する時にメモリ上から解放されます。一方、ローカル変数は関数が呼び出された時にメモリ上に確保されて、関数が終了する時にメモリ上から解放されます。

2006 / Nov / 11 更新

main 関数
 main関数内の2行目でグローバル変数globalIntの値をNSLogを使って表示するようにしています。実行ログ画面には、
 globalInt is 10
と表示されます。関数の外で定義された変数が、そのまま関数内でも使えることが分かります。なおコードの中の %2d は「整数値を右寄せ2桁で表示せよ」という意味です
 main関数の3行目では、main関数の引数として渡された整数値argcを表示しています。実行ログ画面に、
 argc      is  1
と表示されます。このように引数として渡された値はそのまま関数内でローカル変数として使えます。このサンプルコードの場合は、グローバル変数のargcが隠されて関数内のローカル変数であるargcが有効になっています。
 4行目ではargc変数に整数値の55を代入し、5行目で再度argcをログ画面に表示しています。
 argc      is 55
6行目7行目ではそれぞれ funcA 関数と funcB 関数を呼び出しています。

2006 / Nov / 7 更新

funcA 関数
 funcA 関数では、2行目 globalInt という整数値の変数を定義し、50というリテラル値で初期化しています。これはローカル変数となります。この funcA 関数内では、 main.m ファイルの冒頭で定義されたグローバル変数の globalInt は隠れてしまい、ローカル変数の globalInt が使われます。

2006 / Nov / 8 更新

 funcA 関数での空白行を含めての4行目では、 argc という変数の値を表示するようにしています。
このfuncA 関数では argc というローカル変数は定義していませんので、グローバル変数の10という値が表示されます。
 argc      is 10
5行目では、この argc グローバル変数に複合代入演算子を使って元に値に10を加算しています。複合代入演算子についてはコラムで詳しく説明します。
 argc += 10;
そして6行目で、加算された argc を表示しています。
 argc      is 20

2006 / Nov / 9 更新

 続けて、7行目ではglobalIntの値をログ画面に表示しています。
 globalInt is 50
ローカル変数としてのglobalIntの値が表示されていることがわかります。
8行目では、そのローカル変数のglobalIntに30を加えています。そして9行目で、そのglobalIntの値をログ画面に表示しています。
 globalInt is 80

2006 / Nov / 11 更新

funcB 関数
 このfuncB 関数では、ローカル変数の定義は一切行っていません。従って2行目ではグローバル変数としてのglobalIntの値をログ画面に表示しています。
 globalInt is 10
funcA 関数で、funcA 関数内のローカル変数としてのglobalIntの値を色々と設定しましたが、グローバル変数してのglobalIntには一切影響がおよんでいないことがわかります。
3行目でそのグローバル変数のglobalIntの値に20を加えて、4行目でその値をログ画面に表示しています。
 globalInt is 30

main.mのすべてを実行したログ画面は下記(図37)のようになります。
図37


2006 / Nov / 11 更新
2006 / Nov / 12
グローバル変数とvolatile
auto 記憶クラス指定子
 前項の「グローバル変数とローカル変数」の冒頭で、「ローカル変数は関数が呼び出された時にメモリ上に確保されて、関数が終了する時にメモリ上から解放されます。」と述べました。
このように変数を自動的に解放するために用意されているのが auto 記憶クラス指定子です。auto指定された変数は自動的に解放されるので自動変数と呼ばれます。この auto 記憶クラス指定子は C 言語の予約語のひとつです。自動変数を定義するには下記のように記述します。また自動変数は、あくまでもローカル変数のみに指定できます。

auto int localInt = 100;

 しかしローカル変数のほとんどは、関数終了時に自動的に解放されるほうが好ましいので、auto 記憶クラス指定子は省略できることになっています。なにの指定子もついていないローカル変数は自動的に自動変数になることになっています。

int localInt = 100;

 auto 記憶クラス指定子については、C言語予約語一覧 でも説明しています。

2006 / Nov / 12 更新

static 記憶クラス指定子
 グローバル変数はプログラムの起動時から終了時までメモリ上に常駐し値の保持を続けます。一方、ローカル変数(自動変数)は関数が終了するとメモリ上から解放されて保持していた値もなくなります。これはメモリの節約の面で有効であり、また、グローバル変数と違い、その関数内だけで使用できるということは安全性の面からも好ましいことです。
 しかし、メモリの節約を考えないのであれば、その関数内だけで有効で、しかも関数終了後も値を保持しているローカル変数があれば、安全性という面で有効な便利な変数ができます。
 そこでこのような、関数の終了後もメモリ上から解放されずに値を保持するローカル変数を定義することができるのが static 記憶クラス指定子です。static指定された変数は 静的変数 と呼ばれます。

static int staticInt = 100;

 では、前回の「最小構成のコマンドラインツールを作ってみる」を参考にして、「static」というプロジェクトを作ってみてください。面倒であれば前項の「volatile」プロジェクトを使ってもらっても結構です。
 作成した static プロジェクトの main.m ファイルを下記のようにコーディングします。

main.m

#import <Foundation/Foundation.h>

void funcA( int a );           // funcA関数のプロトタイプです
void funcB( int a );           // funcB関数のプロトタイプです

int main( ) {
    funcA( 5 );
    funcA( 5 );
    funcA( 5 );
    funcA( 5 );
    funcA( 5 );

    NSLog(@"\n");
    /* funcA と funcB の実行結果の間に1行の間隔を入れています */

    funcB( 5 );
    funcB( 5 );
    funcB( 5 );
    funcB( 5 );
    funcB( 5 );

    return 0;
}

void funcA( int a ) {
    auto int sum = 0;
    sum += a;                   // += は複合代入演算子です
    NSLog(@"Sum of funcA = %2d", sum);
}

void funcB( int a ) {
    static int sum = 0;
    sum += a;                   // += は複合代入演算子です
    NSLog(@"Sum of funcB = %2d", sum);
}


上記のサンプルコードの実行ログ画面は次のようになります(図38)。

図38


 funcA 関数の自動変数 sum は関数が呼び出されるたびに新たに定義され 0 で初期化されています。そして sum 自動変数は関数が終了するたびにメモリから解放されています。
 それに対して funcB 関数の静的変数 sum は、関数が最初に呼び出された時に1度だけ定義され 0 で初期化されます。funcB 関数が終了しても静的変数 sum はメモリから解放されることなく値を保持します。2度目以降、funcB 関数が呼びだされても静的変数 sum を新たに定義することはなく、初回に呼び出された時に確保した(定義した)静的変数 sum をそのまま使います。

 なお、グローバル変数も静的変数も、そのプログラムが終了する時に消滅します(確保したメモリを解放します)。自動変数は関数が終了した時点で消滅していますので、プログラム終了以前に確保したメモリは解放されています。

2006 / Nov / 13 更新
第7回へ 目次へ