9.プリプロセッサとメイクファイル

9-3. ヘッダーファイル

◇ヘッダーファイルとは?

その名の通り頭になるファイルです。(ぉぃぉぃ)
具体的には、関数のプロトタイプ宣言や構造体・共用体の定義などを書きこみます。
これは、特にメインのソースファイルに書いても問題は無いのですが、ヘッダーファイルに分割する事で次のような利点があります。

1.宣言部と本体を分けることによってプログラムが見やすくなる。また、使われている関数を調べるのが楽になる。

2.分割コンパイルする場合、extern宣言の代わりにヘッダーファイルをインクルードする事で作業を楽にできる。

3.作ったプログラムを再利用しやすくする。
コンパイル済みのライブラリであってもヘッダーファイルがあることで他のプログラムから利用できるようになる。

の3点です。とくに3番目は企業にとっては内部設計を非公開のまま外部からの利用を許可できるので大きな利点です。
逆に、UNIX系OSになるとフリーウェアがソースで公開され、バグがあれば作者に限らず直してくれる(改変も許可)のと、OSに沢山のディストリビューションがあるため、互換性のためにもコンパイルして利用してもらうという点で3番より2番目の利点のほうが大きくなります。

また、必要性としては大きなプロジェクト等、多くのプログラムか1つの大きなアプリケーションを作る時などは、上の理由から絶対必要になります。

◇ヘッダーファイルの作り方

それでは、ヘッダーファイルを作ってみましょう。

1.まず、ヘッダーファイルに書きこむべき内容を調べます。

  extern宣言
  関数のプロトタイプ宣言
  構造体・共用体の定義
  インライン関数の宣言・定義
  マクロ展開の定義
  ・・・など

※この内容はC++の規則を元に書いています、Cではヘッダーについてあまり厳密ではありませんが現在のコンパイラーの多くがC++なのであえて厳密にしています。またC++に移行した時にやりなおすこともないのでそうしています。

ということで、次にヘッダーに書くことをオススメできないもの。

  関数の定義(本体)
  変数(オブジェクト)の宣言
  その他ソースに書くべきもの
  ・・・です。

2.次にヘッダーファイルの拡張子を(.h)にしてなるべくソースと同じディレクトリにいれる。

3.最後に呼出し側のソースからはファイルの先頭付近でインクルードする。

では実際に以下のプログラムをヘッダーとソースの2つに分けます。

/* サンプルプログラム */
#include<stdio.h>
#define PRINT printf
int fadd(int, int);
int x;

main()
{
  int a=2,b=3,c;
  c=fadd(a,b);
  PRINT("c = %d\nx = %d\n",c,x);
}

fadd(int i, int j)
{
  x = i + j;
  return x;
}

/* End Of File */

ここで、ヘッダーに書きこむ対象になるのは
#include<stdio.h>~int fadd(int, int);までです。
int x;をヘッダーにいれるのは好ましくありません。
(オブジェクト宣言は最終的に機械語に翻訳される内容だから)

そして2つに分けた後は以下のようになります。

●ヘッダー(header.h)
/* header.h */
#include<stdio.h>
#define PRINT printf
int fadd(int, int);
/* End Of File */

●ソース(source.c)

/* source.c */
#include"header.h"
int x;

main()
{
  int a=2,b=3,c;
  c=fadd(a,b);
  PRINT("c = %d\nx = %d\n",c,x);
}

fadd(int i, int j)
{
  x = i + j;
  return x;
}

/* End Of File */

となります。