画像(logo)

HOME/[C言語 入門]小学生でもわかるC言語3 目次/十二日目 ソース分割2

広告

[C言語 入門 小学生でもわかるC言語3]
十二日目 ソース分割2

広告

↓発売日:2018年09月22日↓

たった1日で基本が身に付く! C言語 超入門

新品価格
¥2,225から
(2018/10/8 23:10時点)

目次へ戻る

ソース分割2

今回は分割したソース間の変数の受け渡しについてみていきたいと思います。

通常の受け渡し

通常の受け渡しに関しては特に意識する事なくいつも通り行う事ができます。

ファイル名「main.cpp」

/*十二日目 プログラム1その1*/
#include <stdio.h>
#include "func.h"

int main(){
	func(5);
	func(3);

	printf("5 * 5 = %d\n",func2(5));
	printf("3 * 3 = %d\n",func2(3));
		
	return 0;
}

ファイル名「func.h」

/*十二日目 プログラム1その2*/
void func(int count);
int func2(int var);

ファイル名「func.cpp」

/*十二日目 プログラム1その3*/
#include <stdio.h>

void func(int count){
	int i = 0;
	while(i < count){
		printf("%d ",i);
		i++;
	}
	printf("\n");
}

int func2(int var){
	return var * var;
}

■実行結果■

画像(ci_12_1)

このように引数、戻り値を使った通常の変数の受け渡しはいつも通りですね!

グローバル変数

次はグローバル変数の場合です。

グローバル変数を複数のファイルをまたいで使えるようにするには「extern」宣言というものが必要になります。

まずは簡単な例になります。

ファイル名「main.cpp」

/*十二日目 プログラム2その1*/
#include <stdio.h>
#include "func.h"

int suji;

int main(){
	suji = 250;

	func();

	return 0;
}

ファイル名「func.h」

/*十二日目 プログラム2その2*/
void func(void);

ファイル名「func.cpp」

/*十二日目 プログラム2その3*/
#include <stdio.h>

extern int suji;

void func(){
	printf("suji = %d\n",suji);
}

■実行結果■

画像(ci_12_2)

「main.cpp」で宣言したグローバル変数を使えるようにする為に、使いたいファイルで「extern」宣言をしております。

extern int suji;

こちらですね。

この「extern」宣言をする事によって、「どこかにこの変数が宣言されているので、それを使ってください!」みたいな意味になるので「main.cpp」にて宣言されたグローバル変数が使えるようになるというワケです。

ここでグローバル変数を宣言する場所ですが、こちらもプロトタイプ宣言と同じように別に「int main()」と同ファイルでなければならないという事はありません。

ファイル名「main.cpp」

/*十二日目 プログラム3その1*/
#include <stdio.h>
#include "func.h"

extern int suji;

int main(){
	suji = 250;

	func();

	return 0;
}

ファイル名「func.h」

/*十二日目 プログラム3その2*/
void func(void);

ファイル名「func.cpp」

/*十二日目 プログラム3その3*/
#include <stdio.h>

int suji;

void func(){
	printf("suji = %d\n",suji);
}

■実行結果■

画像(ci_12_3)

問題なく実行されたかと思います。

つまりは関数の外(int main(){...}やvoid func(){...}のカッコの外)で宣言された変数がグローバル変数という事になるんですね。

今のプログラムの場合まずファイル名「func.cpp」でグローバル変数「int suji」を宣言しました。

この時点ではこの変数はファイル名「func.cpp」の中でのみ使えるグローバル変数になります。

これをファイル名「main.cpp」で「extern」宣言する事によって共有できるようになったというワケですね。

続いて別々のヘッダファイルにグローバル変数とそれを「extern」宣言したものを記述してみた例です。

ファイル名「main.cpp」

/*十二日目 プログラム4その1*/
#include <stdio.h>
#include "global.h"
#include "func.h"

int main(){
	suji = 100;
	suji2 = 200;
	suji3 = 300;

	func();

	return 0;
}

ファイル名「global.h」

/*十二日目 プログラム4その2*/
int suji;
int suji2;
int suji3;

ファイル名「ex_global.h」

/*十二日目 プログラム4その3*/
extern int suji;
extern int suji2;
extern int suji3;

ファイル名「func.h」

/*十二日目 プログラム4その4*/
void func(void);

ファイル名「func.cpp」

/*十二日目 プログラム4その5*/
#include <stdio.h>
#include "ex_global.h"

void func(){
	printf("suji = %d\n",suji);
	printf("suji2 = %d\n",suji2);
	printf("suji3 = %d\n",suji3);
}

■実行結果■

画像(ci_12_4)

それぞれ別のファイルにまとめたので少しすっきりしましたね!

広告

インクルードガード

最後に同じファイルにおいての変数などの重複宣言エラーを防止するインクルードガードというものを紹介します。

重複宣言とはどういう事でしょうか。

たとえば次のような場合を考えます。

ファイル名「main.cpp」

/*十二日目 プログラム5その1*/
#include <stdio.h>
#include "global.h"
#include "global.h"

int main(){
	suji = 250;

	printf("suji = %d\n",suji);

	return 0;
}

ファイル名「global.h」

/*十二日目 プログラム5その2*/
int suji;

■実行結果■

画像(ci_12_5)

わざと「global.h」を2回続けてインクルードしてみました。

結果は当然エラーになりましたね。

前回説明しましたが、「#include」というのはただ単にそこに指定したファイルの内容が展開されるだけなので、

#include <stdio.h>
int suji;
int suji;

int main(){
	suji = 250;

	printf("suji = %d\n",suji);

	return 0;
}

こんな状態になり、エラーになったという事ですね。

こんなミスはそうそうないかと思われますが中規模以上のプログラムになってくると、複雑にファイルが絡みあい、いつこのような重複宣言エラーが起こるとも限りません。

そこで前回学んだプリプロセッサを使ったプログラミングテクニックでこれを防止します。

まずはわかりやすいように一つのファイルでインクルードガードを試してみた例です。

#include <stdio.h>

#ifndef DEF_VAR_SUJI
#define DEF_VAR_SUJI

int suji;

#endif

#ifndef DEF_VAR_SUJI
#define DEF_VAR_SUJI

int suji;

#endif

int main(){
	suji = 250;

	printf("suji = %d\n",suji);

	return 0;
}

グローバル変数「int suji」を宣言している前後に注目です。

#ifndef DEF_VAR_SUJI
#define DEF_VAR_SUJI

int suji;

#endif

「#ifndef DEF_VAR_SUJI」これは「DEF_VAR_SUJI」が#defineされていない場合は「#endif」までの内容を実行するという意味ですね。

そしてその後の内容を見てみると「DEF_VAR_SUJI」が#defineされグローバル変数「int suji」が宣言されております。

こうしておいてその後同じように記述すれば

#ifndef DEF_VAR_SUJI
#define DEF_VAR_SUJI

int suji;

#endif

すでに「DEF_VAR_SUJI」は#defineされているのでその後の内容は素通りされるというワケです。

では先ほどの分割したファイルにこれを使ってみます。

ファイル名「main.cpp」

/*十二日目 プログラム6その1*/
#include <stdio.h>
#include "global.h"
#include "global.h"

int main(){
	suji = 250;

	printf("suji = %d\n",suji);

	return 0;
}

ファイル名「global.h」

/*十二日目 プログラム6その2*/
#ifndef DEF_GLOBAL_H
#define DEF_GLOBAL_H

int suji;

#endif

■実行結果■

画像(ci_12_6)

今度はうまくいきましたね。

ちなみにあの「stdio.h」にもこのインクルードガードのテクニックが使われていたりします。

なので「#include <stdio.h>」を書きまくってもエラーにはなりません。

ある程度使いまわしそうなヘッダファイルを作った時はぜひ冒頭にこのインクルードガードを加えておきましょう!

ここで勘違いしないで頂きたいのが、

ファイル名「main.cpp」

/*十二日目 プログラム7その1*/
#include <stdio.h>
#include "global.h"
#include "func.h"

int main(){
	suji = 250;

	func();

	return 0;
}

ファイル名「global.h」

/*十二日目 プログラム7その2*/
#ifndef DEF_GLOBAL_H
#define DEF_GLOBAL_H

int suji;

#endif

ファイル名「func.h」

/*十二日目 プログラム7その3*/
void func(void);

ファイル名「func.cpp」

/*十二日目 プログラム7その4*/
#include <stdio.h>
#include "global.h"

void func(){
	printf("suji = %d\n",suji);
}

■実行結果■

画像(ci_12_7)

重複宣言を防止してくれると思いこんな感じで書いても意味はありません。

ファイル名「func.cpp」はインクルードされているワケではないので別ファイルになります。

あくまでも同じファイル内で重複した場合のエラー対策になるので、こんな時は先に説明した「extern」宣言を使ってください。

あと「DEF_GLOBAL_H」の部分は何でもいいのですが、「_DEF_GLOBAL_H」みたいにアンダーバーなどから始めると標準ヘッダのインクルードガードとかぶる恐れがあるのでやめておきましょう。

次回はプログラムの実行中のメモリ確保、解放をやっていきたいと思います。

次回

十三日目 メモリ確保

□ページの先頭へ□

□目次へ戻る□

□HOME□

広告

↓発売日:2016年02月29日↓

12歳からはじめる ゼロからのC言語 ゲームプログラミング教室

新品価格
¥2,462から
(2018/10/8 23:25時点)

↓発売日:2018年06月22日↓

スッキリわかるC言語入門

新品価格
¥2,916から
(2018/10/8 23:15時点)

↓発売日:2018年03月09日↓

C言語本格入門 ~基礎知識からコンピュータの本質まで

新品価格
¥3,218から
(2018/10/8 23:16時点)

↓発売日:2017年06月14日↓

やさしいC 第5版 (「やさしい」シリーズ)

新品価格
¥2,700から
(2018/10/8 23:17時点)

↓発売日:2018年05月21日↓

作って身につく C言語入門

新品価格
¥2,462から
(2018/10/8 23:18時点)

↓発売日:2017年12月07日↓

新・標準プログラマーズライブラリ C言語 ポインタ完全制覇

新品価格
¥2,678から
(2018/10/8 23:19時点)

↓発売日:2017年02月08日↓

新・明解C言語で学ぶアルゴリズムとデータ構造 (明解シリーズ)

新品価格
¥2,700から
(2018/10/8 23:20時点)

↓発売日:2017年09月26日↓

かんたん C言語 [改訂2版] (プログラミングの教科書)

新品価格
¥2,916から
(2018/10/8 23:22時点)