今回は《複数Cソースを管理しよう》というテーマで記事をまとめます。
「複数Cソースの管理」を習得すると、プログラム全体がわかりやすくなります。しっかり学んでいきましょう!
尚、現在執筆中のC言語入門記事は以下の人を対象としています。
- プログラミング未経験の人
- C言語プログラミングの学習をこれから始めたい人
- C言語プログラミングの学習を始めたばかりの人
複数Cソースを管理しよう
複数Cソース管理
今までは1つのCソースファイルに全てのプログラムコードを記述していましたね。
しかし、ある程度大きい規模のプログラムを作成する場合、複数のファイルにプログラムコードを分割して管理したほうがプログラム全体がわかりやすくなります。
尚、実際のシステム開発では1つのソースファイルにプログラムコードが書かれていることはまずありません。つまり、重要度は割と高いということです。
※補足※『Visual Studio』へのCソース追加方法
『Visual Studio』へのCソース追加方法は、<【独学C言語入門③】はじめてのC言語プログラミング【まずは動かしてみよう / Hello World> の 【Cソースファイルを追加して、プログラムコードを書く】をご参照ください。
他のCソースに書かれた関数の呼び出し
他のCソースに書かれた関数を呼び出す場合、呼び出し元の関数が書かれているCソース内に”extern属性”を付与して関数宣言する必要があります。
構文と使用方法は次のようになります。
【構文】
extern 戻り値の型 関数名(引数);
【使用方法】
sub.c
#include <stdio.h> void test1() { printf( "sub.c内のtest関数です\n" ); }
main.c
#include <stdio.h> extern void test1(); void main() { printf( "main関数です\n" ); test1(); }
他のCソースに書かれたglobal変数の使用
他のCソースに書かれたglobal変数を使用する場合、関数と同じように”extern属性”を付与して宣言する必要があります。
構文と使用方法は次のようになります。
【構文】
extern 変数の型 変数名;
【使用方法】
sub.c
int num_global1 = 10; int num_global2 = 20;
main.c
#include <stdio.h> extern int num_global1; extern int num_global2; void main() { printf( "main関数です\n" ); num_global1 = 100; num_global2 = 200; printf( "num_global1 = %d\n", num_global1 ); printf( "num_global2 = %d\n", num_global2 ); }
尚、変数は定義時に初期化を行うことができることはご存じだと思いますが、extern属性付き変数の宣言では初期化を行うことはできません(コンパイルエラーになります)。
extern属性の意味は「どこかにいる変数本体を自分の処理で使用する為の宣言」という認識で覚えてもらっておけば良いと思います。
一般的な「extern属性調関数・変数」の宣言場所
ここまでで紹介したextern属性付き関数・変数の宣言は、呼び出し元の関数が書かれているCソースファイルでしたね。
しかし、この方法だと全ての関数・変数を管理した上で使用したいものをCソース単位で指定しなければなりません。これはいささか面倒ではありますね。
そこで、一般的には次のような構成で実装します。
- 関数・変数が定義されているCソースファイルと対になるようにヘッダーファイル(*.h)を用意
- 上記ヘッダーファイルにextern属性付き関数・変数の宣言を記述
- 呼び出し元関数が書かれたCソースファイル上で上記のヘッダーファイルをインクルード
上記のような構成にすることで、特別な管理をせずに別のCソースファイルに書かれた関数・変数を使用することができるのです。イメージとしては『関数・変数の作成者が公開する関数・変数を決定する』といった感じです。
※補足※『Visual Studio』へのヘッダー追加方法
『Visual Studio』へのヘッダーファイル追加方法はCソースファイルとほぼ同等です。なので、簡単な手順のみ解説します。
① [ソリューションエクスプローラー]内の[ヘッダーファイル]を
右クリックして、[追加] → [新しい項目(W)] をクリック
② 「ヘッダーファイル(.h)」を選択し、「名前」を入力して
「追加」をクリック
③ [ソリューションエクスプローラー]内の[ヘッダーファイル]に
②で入力したヘッダーファイルが追加される
【具体例】
sub.h
extern int num_global_sub; extern void sub();
sub.c
int num_global_sub = 0; void sub() { num_global_sub = 100; }
main.c
#include <stdio.h> #include "sub.h" void main() { sub(); printf( "num_global_sub = %d\n", num_global_sub ); }
※補足※ #includeのファイル指定方法(<>と"")について
#include の後にヘッダーファイルが指定できるのはご存じだと思いますが、指定方法が <> と "" の2つであることに気が付いているでしょうか?
実は <> と "" でファイルの検索方法が異なります。
<> | インクルードパスからファイルを検索 |
"" | 次の2段階でファイルを検索 ①カレントディレクトリからファイルを検索 ②見つからなかった場合、インクルードパスから検索 |
インクルードパスとは、コンパイラに登録できる「インクルード対象ファイル(主にヘッダーファイル)が保存されている場所」です。
当然、『Visual Studio』でも登録することができます(詳細は後日紹介します)。
基本的に「C言語の標準関数などコンパイラが提供している関数を使用したい場合は <> を使用し、自作の関数を使用したい場合は "" を使用する」と覚えておけば問題ないと思います。
サンプル実行
それでは、サンプルを用意したので実行してみてください。
【サンプルコード】
main.c
#include <stdio.h> /* 外部のヘッダーファイルをインクルード */ #include "calcrate.h" #include "global_var.h" void main() { int num1 = 0; int num2 = 0; /* 外部関数の呼び出し */ num1 = add( 1, 2 ); num2 = sub( 1, 2 ); /* 計算結果表示 */ printf( "num1 = %d\n", num1 ); printf( "num2 = %d\n", num2 ); printf( "\n" ); /* 外部のglobal変数を表示 */ printf( "global_num = %d\n", global_num ); printf( "\n" ); /* 外部のglobal変数を更新 */ global_num = 100; /* 外部関数の呼び出し(外部のglobal変数を表示) */ print_global_num(); /* 外部関数の呼び出し(外部のglobal変数を更新) */ update_global_num( 200 ); /* 外部のglobal変数を表示 */ printf( "global_num = %d\n", global_num ); printf( "\n" ); }
・calcrate.h
extern int add(int a, int b); extern int sub(int a, int b);
・calcrate.c
int add(int a, int b){ return a + b; } int sub(int a, int b){ return a - b; }
・global_var.h
extern int global_num; extern void print_global_num(); extern void update_global_num(int num);
・global_var.c
#include <stdio.h> int global_num = 0; void print_global_num(){ printf( "print_global_num関数内です。\n" ); printf( " global_num = %d\n", global_num ); printf( "\n" ); } void update_global_num( int num ){ global_num = num; }
【実行結果】
次回は「マクロ」
今回は「複数Cソースの管理」について学んでもらいました。
次回は「マクロ」について解説します。「マクロ」を習得すると、より簡略化したプログラムコードを書くことができるようになります。
ご期待ください。