リンク

翻訳単位とリンク

大きなプログラムの全てのソースコードを1つとして扱ってしまうと、コンパイルにかなり時間がかかり、 途中で失敗するとそれまでの処理結果が無駄になってしまうことがあります。 そこで, ソースコードを分割します。この分割する単位を翻訳単位といい、 通常ファイルが翻訳単位になります。

リンクしてみる

実際にリンクしてみましょう。まずはソースコードを用意します。 翻訳単位外で定義された関数のがあることを知らせるため、 プロトタイプ宣言を書いたヘッダファイルを作成し、インクルードしておきましょう。

では、リンクしましょう。リンクするコマンドを書いても良いのですが、 リンクを適切に、かつ自動的に行うツールとしてmakeがあります。 makeにはMakefileと呼ばれるファイルで情報を伝えます。 Makefileの詳細については説明を省きます。

作成したら, "make"と端末に入力します. makeはMakefileという名のファイルが現在のディレクトリにあると自動的にそれを処理します. 通常, Makefileは実行したコマンドを標準出力に出力します.

$ make
cc    -c -o main.o main.c
cc    -c -o func.o func.c
cc   main.o func.o -o a.out
$

ccはコンパイラです。-cオプションで実行ファイルではなく、リンクに適した形式にコンパイルします。 これはオブジェクトファイルと呼ばれます。最後に、ccはリンクを行っています。 この時、ccは標準Cライブラリなど必要なファイルと共にリンカと呼ばれるプログラムにリンクさせています。

リンケージとstatic修飾子

リンケージは、データに割り当てられたシンボルの参照を指します。例えば、 先程の例ではfuncは文字配列を返す関数のシンボルで、main関数ないとリンケージがあります。

ところが、リンケージには問題があります。それはリンクが大きなプログラムを作る際に行われるということです。
例えば、他人 (1分前の自分も含む) がプログラム内で同じ名前の関数を作成しようとしたり (名前空間の制約)、 リンクすべきではない関数にリンクしてしまうということが多くあります。
また、リンケージがあるかどうかわからないため、不用意にコードを変更できなくなってしまうという問題もあります。 同時に、コンパイラが関数を他の関数に埋め込むインライン展開などといった最適化をするのを阻害します。

そこで使われるのがstatic修飾子です。static修飾子がついた関数は翻訳単位の外部からのリンケージがありません (内部リンケージ) 。そのことを示すため、外部から呼び出されないものは必ずstatic修飾子をつけましょう。 例え1人で開発していても1分後の自分やコンパイラも他人だと思って、彼らに分かるように書くのが大前提です。