C言語教室 第30回 複数に分かれたソースファイル
前回の教室では、C言語のソースファイルが2つ以上あるときにどのようにコンパイルするのかを簡単に説明しました。実はひとつになっているソースコードを2つのファイルに分けるにはちょっとした工夫が必要です。単純に分けるだけではエラーが出てしまいます。
もう随分昔になってしまいましたが、第1回の教室で使ったプログラムを例にファイルを分けてみましょう。
C言語教室 第1回 - 関数呼び出し
#include <stdio.h>
int a;
int b;
void ave() {
int v;
v = (a + b) / 2;
printf("Ave(%d,%d)=%d\n", a, b, v);
}
void main() {
a = 2;
b = 9;
ave();
}
この時に、この順序でave関数とmain関数が書かれていれば問題ないのですが、この順序を変えてしまった場合には、main関数の中でまだ宣言されていないave関数が登場するのでエラーとなるので、
extern void ave();
というオマジナイが必要です。と説明したのを思い出してください。実は、この書き方は微妙なところがあるのですが、そこは追って説明します。
C言語の文には、大雑把に言って名前を宣言だけする文と、その宣言の中身を定義する文があります。C言語を始め最近の多くのコンパイル言語は1パスといって、プログラムの最初から順に1回だけプログラムを読んで、CPUが実行する命令が入っている中間的なファイルや実行ファイルを作ります。ですから、関数名や変数名と言った名前を「使う」よりも「前」に、その宣言が出てくる必要があります。
先の例だと関数より前にaとbの宣言があり、ave関数の中で最初にvの宣言があるので、その次の行でvもaもbも、その意味がわかっているので正しくコンパイルできるのです。
#include <stdio.h>
int a;
int b;
extern void ave();
void main() {
a = 2;
b = 9;
ave();
}
void ave() {
int v;
v = (a + b) / 2;
printf("Ave(%d,%d)=%d\n", a, b, v);
}
ave関数よりも前にmain関数を持ってくると、aもbも関数より先に宣言してあるので大丈夫ですが、extern で始まる行が無いとave関数を呼び出す(使う)時点では、まだave関数についての宣言が無いので「この名前はいったいなんだろう?」ということになって解釈ができずにエラーになってしまうわけです。そこで extern で始まる行を書くことで、aveという名前は(戻り値も引き数もない)関数なんだよと教えてあげるわけです。これでave関数の中身はわからないけど、ともかく関数ということがわかっているのでコンパイルできるようになるのです。このように名前を使う時には、その名前が何であるかを先に書いてある必要があることを覚えてください。
これを踏まえて先のプログラムを main関数だけのある main.c と ave関数だけがある ave.c の2つに分けてみましょう。
[ave.c]
#include <stdio.h>
int a;
int b;
void ave() {
int v;
v = (a + b) / 2;
printf("Ave(%d,%d)=%d\n", a, b, v);
}
[main.c]
extern void ave();
extern int a;
extern int b;
void main() {
a = 2;
b = 9;
ave();
}
インクルードは printf を使うのに必要なので、printf を呼んでいない main.c には不要です。main.c では、このファイルに含まれていない ave関数だけではなく、aとbについても extern が必要です。つまり extern というのは「他のファイル」という意味なんです。
この他のファイルにある名前については、コンパイルの際ではなく、リンクという最後に複数の中間ファイルをひとつの実行ファイルにまとめる際にチェックされます。ave関数の中身がどこにもなかったり、aの中身が2つあったりすれば、そこでエラーになるのです。もちろん型が違ってもダメです。
このようにプログラムは最初から順に解釈されるので、名前を使う前に必ず宣言が必要で、ひとつのソースファイルごとに「コンパイル」されて中間ファイルが作られ、最後にひとつのファイルに「リンク」されて実行できるようになるのです。
今回も課題はありません。次回はインクルードファイルについて説明します。
ヘッダ画像は、いらすとや さんよりhttps://www.irasutoya.com/2016/07/blog-post_807.html
この記事が気に入ったらサポートをしてみませんか?