🐡

「.h」ファイルはなぜ「.h」ファイルなのか?

2024/02/03に公開

はじめに

今回は古のC言語やC++言語で使われているヘッダーファイルについて深堀してみたい。
このヘッダーファイルは入門書で当たり前のものとして扱われているがよくよく考えると不思議なものである。
CやC++では翻訳単位間の仲立ちをするものだが、同じようなコンパイル型言語でもRustやGo言語では消え去っているものである。

今、私がわかっている範囲でこのヘッダーファイルについて深堀したいと思う。

ヘッダーファイルに関する実験

まずコンパイラにとってこの「.h」ファイルが特別なものなのか歴史的経緯から便宜的に「.h」ファイルとされているのかを検証する。

https://github.com/Embeded-ojisan/include_test

そのために以下の2つのファイルを用意する。

main.c
#include "sub.b"

int main()
{
    func();
}

まずはmain.cである。これはmain関数内部で外部公開されているfuncという関数を呼び出す。ただし、func用のヘッダーが本来、sub.hであるところをsub.bとしている。もしコンパイラにとって「.h」ファイルが特別な意味を示すならなにがしかのエラーが出てくるはずである。

sub.b
#ifndef INCLUDE_G
#define INCLUDE_G

#define func() printf("sucess");

#endif

次にヘッダーファイルとしてのsub.bである。内部ではfuncをprintfに書き換えるプリプロセスが仕込んである。もしこれが展開されると書き換わる。

gcc main.c

として実行するとなんと結果は「sucess」という文字列が出力された。つまり、sub.bの内容がmain.cに展開されたことになる。ということはコンパイラとしては「.h」等の拡張子は気にしておらずincludeディレクティブが翻訳単位等にあれば機械的に内容を展開していることになる。(よくよく考えるとたまにstatic関数のユニットテストを実現するため等でソースファイルをincludeしているものを見かけたりはするが…)

おそらく分割コンパイルのつなぎとしてヘッダーファイルを利用する場合も「.b」ファイルで問題がないはずだ。結局のところ、ヘッダーファイルとしてやりたいことはinclude元のソースファイルに情報を展開してシンボル解決をしやすくしているだけなので。

そう考えると「.h」ファイルは歴史的経緯でそういう名前になったのだろうがどういう経緯で「.h」ファイルと呼ばれることになったのだろうか?

「.h」ファイルとは

と思って軽く調べてみたがそれらしき情報はなかった。

https://ja.wikipedia.org/wiki/ヘッダ_(コンピュータ)

wikipediaを参照してみると(wikipediaの情報が信用に値するかは賛否両論あるが)、「ファイルやパケットなどの先頭にあるデータ」という情報技術全般で共通する概念の一例としてヘッダーファイルが紹介されている。

確かに基本的にヘッダーファイルはソースファイルの先頭付近でincludeディレクティブにより展開される「ファイルの先頭にあるデータ」に相当するものなので間違いではないのかもしれない。

この整理の仕方を見るに、情報技術全般でヘッダという概念があり、C言語の誕生時にその概念にちなんで「.h」ファイルという形式が便宜的に作成されたのかもしれない。

最後に

現状、私が調べた範囲ではこの程度しかわかっておりません。もし詳しい方がいればコメント欄等でお教えいただけるとありがたいです。

Discussion