【C】初めてのC言語（11. ヘッダファイル）

# はじめに

* これまでの学習に続いて、今回はヘッダファイルについて学んだ結果をまとめてみました。
  * [【C】初めてのC言語（1. Hello world）](https://qiita.com/nkojima/items/518c1a4ec06861d74b3c)
  * [【C】初めてのC言語（2. 四則演算とフォーマット指定子）](https://qiita.com/nkojima/items/36ea93b7296ce9e8a55b)
  * [【C】初めてのC言語（3. ポインタ）](https://qiita.com/nkojima/items/825bb9f931016faccd68)
  * [【C】初めてのC言語（4. 構造体）](https://qiita.com/nkojima/items/40a1101f2f6f5800bc2d)
  * [【C】初めてのC言語（5. 関数）](https://qiita.com/nkojima/items/1fa3317c04f25fe24276)
  * [【C】初めてのC言語（6. 配列）](https://qiita.com/nkojima/items/eda3ff6675b47e7ab5f0)
  * [【C】初めてのC言語（7. for文）](https://qiita.com/nkojima/items/a5659098f7e5275a96ec)
  * [【C】初めてのC言語（8. 2次元配列）](https://qiita.com/nkojima/items/f5eb25a4f8d1725faa89)
  * [【C】初めてのC言語（9. 関数のプロトタイプ宣言）](https://qiita.com/nkojima/items/57318d74bdfa670bf72e)
  * [【C】初めてのC言語（10. 構造体配列）](https://qiita.com/nkojima/items/75530a3ca63924a14397)

# 学習環境

* 今回は[paiza.io](https://paiza.io/ja/projects/new)のC言語のエディタを使いました。

# ヘッダファイルとは

## 概要

* C言語のソースプログラムは「ソースファイル」「ヘッダーファイル」の2つで構成されています。
* ソースファイルが肥大化した場合は複数のソースファイルに分割すると保守性が向上しますが、その場合は別ファイルに存在する関数などを利用できなくなってしまいます。
* この時に個々の関数、オブジェクト、データ型などの宣言をして、別のソースファイルから利用できる状態にする（外部に公開する）のがヘッダファイルとなります。
  * おそらくこれ以外にもヘッダファイルを作るメリットがあるとは思いますが...

## 書き方のルール

* ヘッダファイルが複数のソースファイルで読み込まれる（インクルードされる）と、重複定義となってコンパイルエラーになってしまいます。
* そこでヘッダファイルを書く時は、以下の`Point.h`のようにヘッダファイルの内容を「インクルードガード」というもので囲むことで安全にインクルードすることが出来ます。（[※参考URL](https://www.jpcert.or.jp/sc-rules/c-pre06-c.html)）
* インクルードガードを使うと、以下のように処理されるので重複定義とはならないそうです。
  * 最初に`Point.h`をインクルードした時は、その内容が全てインクルードされる。
  * 2回以上`Point.h`をインクルードした時は、その内容はインクルードされない（バイパスされる）。
* [こちらの記事](https://qiita.com/MoriokaReimen/items/7c83ebd0fbae44d8532d)だと、インクルードガードを`#ifndef ... #define ... ～ #endif`ではなく、`#pragma once`と一行で表現できる書き方が紹介されていました。
  * ただし`#pragma once`は使えない環境があるらしいので、今回は`#ifndef ... #define ... ～ #endif`を採用しました。
* また、**ヘッダファイル中で「構造体の型の定義」や「関数のプロトタイプ宣言」などはできても、「グローバル変数の定義」と「関数そのものの定義」はNG**だそうです。
* 加えて、[標準ヘッダファイル名を再利用しない](https://www.jpcert.or.jp/sc-rules/c-pre04-c.html)というルールもあるため、命名の際には注意が必要です。

```c:Point.h
#ifndef POINT_H
#define POINT_H

...    // Point.hの内容を記述する。

#endif // POINT_H
```

# サンプルコード

* 上記の「ヘッダファイルの書き方のルール」を踏まえて、以下のコードを作成しました。
  * 位置に関わる処理をまとめた`Point.c`。
  * 位置を表現する構造体の定義と、位置に関わる処理のプロトタイプ宣言をまとめた`Point.h`。
* 短いコードですが、処理をグルーピングして別のファイル（.c)にまとめることで、少しコードがスッキリした気がします（※個人の感想です） 

```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);
}
```

```c: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
```

```c: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;
}
```

```text:実行結果
X座標は2、Y座標は3です。
X座標は3、Y座標は5です。
```

# 参考URL

* [第7日目：ファイル分割 - 一週間で身につくC言語の基本](https://c-lang.sevendays-study.com/day7.html)
* [C初心者が知っておきたいヘッダーファイルとリンクの基礎知識](https://atmarkit.itmedia.co.jp/ait/articles/1404/11/news045.html)
* [ヘッダファイル - Wikipedia](https://ja.wikipedia.org/wiki/%E3%83%98%E3%83%83%E3%83%80%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB)
* [PRE04-C. 標準ヘッダファイル名を再利用しない](https://www.jpcert.or.jp/sc-rules/c-pre04-c.html)
* [PRE06-C. ヘッダファイルはインクルードガードで囲む](https://www.jpcert.or.jp/sc-rules/c-pre06-c.html)
* [C言語 ヘッダファイルの書き方【サンプルフォーマットを公開】](https://monozukuri-c.com/langc-headerfile/)
* [ヘッダファイルの書き方](https://qiita.com/MoriokaReimen/items/7c83ebd0fbae44d8532d)