これはおそらくあなたが望んだよりも詳細な答えですが、きちんとした説明は正当化されると思います。
CおよびC ++では、1つのソースファイルが1つの翻訳単位として定義されます。慣例により、ヘッダーファイルは関数宣言、型定義、およびクラス定義を保持します。実際の関数の実装は、変換単位、つまり.cppファイルにあります。
この背後にある考え方は、関数とクラス/構造体メンバー関数が一度コンパイルおよびアセンブルされると、他の関数は重複を作らずに1か所からそのコードを呼び出すことができるということです。関数は暗黙的に「extern」として宣言されます。
/* Function declaration, usually found in headers. */
/* Implicitly 'extern', i.e the symbol is visible everywhere, not just locally.*/
int add(int, int);
/* function body, or function definition. */
int add(int a, int b)
{
return a + b;
}
関数を翻訳単位に対してローカルにしたい場合は、それを「静的」として定義します。これは何を意味するのでしょうか?つまり、extern関数を使用してソースファイルをインクルードすると、コンパイラが同じ実装を複数回検出するため、再定義エラーが発生します。したがって、すべての翻訳単位に関数宣言は表示するが、関数本体は表示しないようにする必要があります。
それで、最後にどうやって一緒につぶされるのですか?それがリンカの仕事です。リンカは、アセンブラステージによって生成されたすべてのオブジェクトファイルを読み取り、シンボルを解決します。先ほど言ったように、シンボルは単なる名前です。たとえば、変数または関数の名前です。関数を呼び出す、または型を宣言する変換単位がそれらの関数または型の実装を知らない場合、それらのシンボルは未解決と呼ばれます。リンカは、未定義のシンボルを保持する変換ユニットを、実装を含むシンボルと一緒に接続することにより、未解決のシンボルを解決します。ふew。これは、コードに実装されているか、追加のライブラリによって提供されているかに関係なく、外部から見えるすべてのシンボルに当てはまります。ライブラリは、実際には再利用可能なコードを含む単なるアーカイブです。
2つの注目すべき例外があります。まず、小さな関数があればインライン化できます。つまり、生成されたマシンコードはextern関数呼び出しを生成しませんが、文字通りインプレースで連結されます。通常は小さいため、サイズのオーバーヘッドは問題になりません。それらが機能する方法で静的であると想像できます。したがって、ヘッダーにインライン関数を実装しても安全です。クラスまたは構造体定義内の関数実装も、コンパイラによって自動的にインライン化されることがよくあります。
その他の例外はテンプレートです。コンパイラーは、インスタンス化するときにテンプレートタイプ定義全体を確認する必要があるため、スタンドアロン関数や通常のクラスのように、定義から実装を分離することはできません。まあ、これはおそらく今では可能ですが、「export」キーワードに対する広範なコンパイラサポートの取得には長い時間がかかりました。したがって、「エクスポート」のサポートがない場合、インライン関数が機能するのと同じように、翻訳単位はインスタンス化されたテンプレートタイプと関数のローカルコピーを取得します。「エクスポート」のサポートにより、これは当てはまりません。
2つの例外については、インライン関数、テンプレート関数、テンプレート型の実装を.cppファイルに入れてから、.includeで.cppファイルを作成する方が「いい」と感じる人もいます。これがヘッダーであるかソースファイルであるかは重要ではありません。プリプロセッサは気にせず、単なる慣例です。
C ++コード(いくつかのファイル)から最終的な実行可能ファイルまでのプロセス全体の概要:
- プリプロセッサは「#」で始まるすべてのディレクティブを解析しており、実行されます。#includeディレクティブは、たとえば、インクルードされたファイルを下位のものと連結します。また、マクロ置換とトークン貼り付けも行います。
- 実際のコンパイラは、プリプロセッサステージの後に中間テキストファイルで実行され、アセンブラコードを発行します。
- アセンブラアセンブリファイルと発するマシンコードで実行され、これは通常呼ばれるオブジェクトファイルを、問題の動作システムのバイナリ実行可能形式に従います。たとえば、WindowsはPE(ポータブル実行可能形式)を使用し、LinuxはUnix拡張機能付きのUnix System V ELF形式を使用します。この段階では、シンボルは未定義としてマークされています。
- 最後に、リンカが実行されます。前のステージはすべて、各翻訳単位で順番に実行されました。ただし、リンカステージは、アセンブラによって生成されたすべての生成オブジェクトファイルで機能します。リンカはシンボルを解決し、セクションやセグメントの作成のような多くの魔法を行います。これは、ターゲットプラットフォームとバイナリ形式に依存します。プログラマーはこれを一般的に知っている必要はありませんが、場合によっては確かに役立ちます。
繰り返しになりますが、これはあなたが要求したよりも明らかに上でしたが、細部にまでこだわった詳細が全体像を理解するのに役立つことを願っています。