「.h」ファイルはなぜ「.h」ファイルなのか?
はじめに
今回は古のC言語やC++言語で使われているヘッダーファイルについて深堀してみたいです。
このヘッダーファイルは入門書で当たり前のものとして扱われているがよくよく考えると不思議なものです。
CやC++では翻訳単位間の仲立ちをするものですが、同じようなコンパイル型言語でもRustやGo言語では消え去っています。
今、私がわかっている範囲でこのヘッダーファイルについて深堀したいと思います。
ヘッダーファイルに関する実験
まずコンパイラにとってこの「.h」ファイルが特別なものなのか歴史的経緯から便宜的に「.h」ファイルとされているのかを検証します。
そのために以下の2つのファイルを用意します。
#include "sub.b"
int main()
{
func();
}
まずはmain.cについて解説します。これはmain関数内部で外部公開されているfuncという関数を呼び出します。ただし、func用のヘッダーが本来、sub.hであるところをsub.bとしています。もしコンパイラにとって「.h」ファイルが特別な意味を示すならなにがしかのエラーが出てくるはずです。
#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」ファイルとは
と思って軽く調べてみたがそれらしき情報はなかったです。
wikipediaを参照してみると(wikipediaの情報が信用に値するかは賛否両論あるが)、「ファイルやパケットなどの先頭にあるデータ」という情報技術全般で共通する概念の一例としてヘッダーファイルが紹介されています。
確かに基本的にヘッダーファイルはソースファイルの先頭付近でincludeディレクティブにより展開される「ファイルの先頭にあるデータ」に相当するものなので間違いではないのかもしれないです。
この整理の仕方を見るに、情報技術全般でヘッダという概念があり、C言語の誕生時にその概念にちなんで「.h」ファイルという形式が便宜的に作成されたのかもしれないです。
最後に
現状、私が調べた範囲ではこの程度しかわかって状況です。もし詳しい方がいればコメント欄等でお教えいただけるとありがたいです。
Discussion