はじめに
- これまでの学習に続いて、今回はヘッダファイルについて学んだ結果をまとめてみました。
学習環境
- 今回はpaiza.ioのC言語のエディタを使いました。
ヘッダファイルとは
概要
- C言語のソースプログラムは「ソースファイル」「ヘッダーファイル」の2つで構成されています。
- ソースファイルが肥大化した場合は複数のソースファイルに分割すると保守性が向上しますが、その場合は別ファイルに存在する関数などを利用できなくなってしまいます。
- この時に個々の関数、オブジェクト、データ型などの宣言をして、別のソースファイルから利用できる状態にする(外部に公開する)のがヘッダファイルとなります。
- おそらくこれ以外にもヘッダファイルを作るメリットがあるとは思いますが...
書き方のルール
- ヘッダファイルが複数のソースファイルで読み込まれる(インクルードされる)と、重複定義となってコンパイルエラーになってしまいます。
- そこでヘッダファイルを書く時は、以下の
Point.h
のようにヘッダファイルの内容を「インクルードガード」というもので囲むことで安全にインクルードすることが出来ます。(※参考URL) - インクルードガードを使うと、以下のように処理されるので重複定義とはならないそうです。
- 最初に
Point.h
をインクルードした時は、その内容が全てインクルードされる。 - 2回以上
Point.h
をインクルードした時は、その内容はインクルードされない(バイパスされる)。
- 最初に
-
こちらの記事だと、インクルードガードを
#ifndef ... #define ... ~ #endif
ではなく、#pragma once
と一行で表現できる書き方が紹介されていました。- ただし
#pragma once
は使えない環境があるらしいので、今回は#ifndef ... #define ... ~ #endif
を採用しました。
- ただし
- また、ヘッダファイル中で「構造体の型の定義」や「関数のプロトタイプ宣言」などはできても、「グローバル変数の定義」と「関数そのものの定義」はNGだそうです。
- 加えて、標準ヘッダファイル名を再利用しないというルールもあるため、命名の際には注意が必要です。
Point.h
#ifndef POINT_H
#define POINT_H
... // Point.hの内容を記述する。
#endif // POINT_H
サンプルコード
- 上記の「ヘッダファイルの書き方のルール」を踏まえて、以下のコードを作成しました。
- 位置に関わる処理をまとめた
Point.c
。 - 位置を表現する構造体の定義と、位置に関わる処理のプロトタイプ宣言をまとめた
Point.h
。
- 位置に関わる処理をまとめた
- 短いコードですが、処理をグルーピングして別のファイル(.c)にまとめることで、少しコードがスッキリした気がします(※個人の感想です)
Main.c
#include <stdio.h>
#include "Point.h"
int main(void){
Point p = { .x = 2, .y = 3 };
printLocation(&p);
// 位置をずらす。
move(&p, 3, 5);
printLocation(&p);
}
Point.h
#ifndef POINT_H
#define POINT_H
// 構造体:位置型
typedef struct Point {
int x; // X座標
int y; // Y座標
} Point;
// [プロトタイプ宣言]位置を標準出力する。
void printLocation(Point*);
// [プロトタイプ宣言]指定した座標に移動させる。
void move(Point*, int, int);
#endif // POINT_H
Point.c
#include <stdio.h>
#include "Point.h"
// 位置を標準出力する。
void printLocation(Point* point) {
printf("X座標は%d、Y座標は%dです。\n", point->x, point->y);
}
// 指定した座標に移動させる。
void move(Point* point, int x, int y) {
point->x = x;
point->y = y;
}
実行結果
X座標は2、Y座標は3です。
X座標は3、Y座標は5です。