static 関数や static 変数をヘッダーに2015年09月19日 12時40分29秒

何故だか知らないが、チョコチョコ見付ける摩訶不思議な関数と変数。static 関数や static 変数が .h のヘッダファイルに書かれているのを良く見付ける。あちこちで見たことがあるし、消しても消しても誰かが復活させる。

static 関数や static 変数をヘッダファイルに書くのは大間違い。

C++ ではあれこれと新しい意味も増えた。基本の C 言語由来の static はこうだ。static 修飾子を付けると、関数や変数がコンパイル単位内でしか、見えなくなるのだ。extern を付けて、広域で使い回すのと逆になる。

さて、問題はここからだ。ヘッダーファイルのコンパイル単位はそれを #include する各々のファイルだ。何が起きるのかというと、ヘッダーファイルに書かれた static 関数と static 変数は各々のオブジェクトファイルに生成される。

つまり、ヘッダーファイルに書かれた static 関数と static 変数はそれを読み込むファイルの数だけ生成される事になる。同じ関数がいくつも定義されているのに何故エラーにならないかと言うと static 関数だからだ。staic 関数なので、各々の .c や .cpp を越えてリンカーが参照させることは無い。そのため、シンボルの重複が起きないのだ。ヘッダファイルの内容と .c や .cpp ファイルの内容はプリプロセッサに処理されてからコンパイラに渡される。そのため、コンパイラが見るのは大きなファイルが一つだけ。プリプロセッサにどのファイルからどこの行が読まれたかの情報は組み込まれているが、それらを元に、static 関数がヘッダーファイルにあるのを警告するコンパイラは、知る限りでは無い。

static 関数や static 変数をヘッダファイルに見付けたら、即刻修正の対象だ。厄介なことに、コンパイラやリンカーはこの問題を検出しない。また、間違ってはいても、問題の無い動作をすることが多いのも特徴だ。具体的な問題としては、コンパイルに掛かる時間が増える。リンカーも時間が掛かる。実行形式のファイルの大きさが増える。実行時のメモリの利用量も増えるなど多岐にわたる。