広告
↓発売日:2018年09月22日↓
新品価格 |
今回は分割したソース間の変数の受け渡しについてみていきたいと思います。
通常の受け渡しに関しては特に意識する事なくいつも通り行う事ができます。
/*十二日目 プログラム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; }
/*十二日目 プログラム1その2*/ void func(int count); int func2(int var);
/*十二日目 プログラム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; }
このように引数、戻り値を使った通常の変数の受け渡しはいつも通りですね!
次はグローバル変数の場合です。
グローバル変数を複数のファイルをまたいで使えるようにするには「extern」宣言というものが必要になります。
まずは簡単な例になります。
/*十二日目 プログラム2その1*/ #include <stdio.h> #include "func.h" int suji; int main(){ suji = 250; func(); return 0; }
/*十二日目 プログラム2その2*/ void func(void);
/*十二日目 プログラム2その3*/ #include <stdio.h> extern int suji; void func(){ printf("suji = %d\n",suji); }
「main.cpp」で宣言したグローバル変数を使えるようにする為に、使いたいファイルで「extern」宣言をしております。
extern int suji;
こちらですね。
この「extern」宣言をする事によって、「どこかにこの変数が宣言されているので、それを使ってください!」みたいな意味になるので「main.cpp」にて宣言されたグローバル変数が使えるようになるというワケです。
ここでグローバル変数を宣言する場所ですが、こちらもプロトタイプ宣言と同じように別に「int main()」と同ファイルでなければならないという事はありません。
/*十二日目 プログラム3その1*/ #include <stdio.h> #include "func.h" extern int suji; int main(){ suji = 250; func(); return 0; }
/*十二日目 プログラム3その2*/ void func(void);
/*十二日目 プログラム3その3*/ #include <stdio.h> int suji; void func(){ printf("suji = %d\n",suji); }
問題なく実行されたかと思います。
つまりは関数の外(int main(){...}やvoid func(){...}のカッコの外)で宣言された変数がグローバル変数という事になるんですね。
今のプログラムの場合まずファイル名「func.cpp」でグローバル変数「int suji」を宣言しました。
この時点ではこの変数はファイル名「func.cpp」の中でのみ使えるグローバル変数になります。
これをファイル名「main.cpp」で「extern」宣言する事によって共有できるようになったというワケですね。
続いて別々のヘッダファイルにグローバル変数とそれを「extern」宣言したものを記述してみた例です。
/*十二日目 プログラム4その1*/ #include <stdio.h> #include "global.h" #include "func.h" int main(){ suji = 100; suji2 = 200; suji3 = 300; func(); return 0; }
/*十二日目 プログラム4その2*/ int suji; int suji2; int suji3;
/*十二日目 プログラム4その3*/ extern int suji; extern int suji2; extern int suji3;
/*十二日目 プログラム4その4*/ void func(void);
/*十二日目 プログラム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); }
それぞれ別のファイルにまとめたので少しすっきりしましたね!
広告
最後に同じファイルにおいての変数などの重複宣言エラーを防止するインクルードガードというものを紹介します。
重複宣言とはどういう事でしょうか。
たとえば次のような場合を考えます。
※ヘッダファイルに「#pragma once」文が表記されている場合はここからは消した状態でプログラムを書いてください!
/*十二日目 プログラム5その1*/ #include <stdio.h> #include "global.h" #include "global.h" int main(){ suji = 250; printf("suji = %d\n",suji); return 0; }
/*十二日目 プログラム5その2*/ int suji;
わざと「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されているのでその後の内容は素通りされるというワケです。
では先ほどの分割したファイルにこれを使ってみます。
/*十二日目 プログラム6その1*/ #include <stdio.h> #include "global.h" #include "global.h" int main(){ suji = 250; printf("suji = %d\n",suji); return 0; }
/*十二日目 プログラム6その2*/ #ifndef DEF_GLOBAL_H #define DEF_GLOBAL_H int suji; #endif
今度はうまくいきましたね。
ちなみにあの「stdio.h」にもこのインクルードガードのテクニックが使われていたりします。
なので「#include <stdio.h>」を書きまくってもエラーにはなりません。
ある程度使いまわしそうなヘッダファイルを作った時はぜひ冒頭にこのインクルードガードを加えておきましょう!
ここで勘違いしないで頂きたいのが、
/*十二日目 プログラム7その1*/ #include <stdio.h> #include "global.h" #include "func.h" int main(){ suji = 250; func(); return 0; }
/*十二日目 プログラム7その2*/ #ifndef DEF_GLOBAL_H #define DEF_GLOBAL_H int suji; #endif
/*十二日目 プログラム7その3*/ void func(void);
/*十二日目 プログラム7その4*/ #include <stdio.h> #include "global.h" void func(){ printf("suji = %d\n",suji); }
重複宣言を防止してくれると思いこんな感じで書いても意味はありません。
ファイル名「func.cpp」はインクルードされているワケではないので別ファイルになります。
あくまでも同じファイル内で重複した場合のエラー対策になるので、こんな時は先に説明した「extern」宣言を使ってください。
あと「DEF_GLOBAL_H」の部分は何でもいいのですが、「_DEF_GLOBAL_H」みたいにアンダーバーなどから始めると標準ヘッダのインクルードガードとかぶる恐れがあるのでやめておきましょう。
プログラミングテクニックの一つとして「#define」を使ったインクルードガードのやり方を紹介しましたが、今はもっと便利なやり方があるのでそちらを紹介します。
そうです。
「#pragma once」とかいうやつです。
これをガードしたいヘッダファイルに書くだけでガードしてくれます。
さきほどのプログラムで試してみましょう。
/*十二日目 プログラム7その1*/ #include <stdio.h> #include "global.h" #include "global.h" int main(){ suji = 250; printf("suji = %d\n",suji); return 0; }
/*十二日目 プログラム7その2*/ #pragma once int suji;
いとも簡単にうまくいきましたね。
インクルードガードに関してはこれからはこちらを使えば良さそうですね!
次回はプログラムの実行中のメモリ確保、解放をやっていきたいと思います。
広告
↓発売日:2016年02月29日↓
12歳からはじめる ゼロからのC言語 ゲームプログラミング教室 新品価格 |
↓発売日:2018年06月22日↓
新品価格 |
↓発売日:2018年03月09日↓
新品価格 |
↓発売日:2017年06月14日↓
新品価格 |
↓発売日:2018年05月21日↓
新品価格 |
↓発売日:2017年12月07日↓
新品価格 |
↓発売日:2017年02月08日↓
新・明解C言語で学ぶアルゴリズムとデータ構造 (明解シリーズ) 新品価格 |
↓発売日:2017年09月26日↓
新品価格 |