C 言語をコンパイルすると、「.OBJ」バイナリ ファイル (オブジェクト ファイル) が生成されます。 C言語では、ソースプログラム(.cファイル)がコンパイラによってコンパイルされた後、接尾辞「.OBJ」が付いたバイナリファイル(オブジェクトファイルと呼ばれます)が生成され、これを「リンク」と呼びます。ソフトウェアは、この「.OBJ」ファイルを C 言語が提供するさまざまなライブラリ関数と接続して、拡張子「.EXE」を持つ実行可能ファイルを生成します。
#このチュートリアルの動作環境: Windows7 システム、C99 バージョン、Dell G3 コンピューター。
C言語ソースファイルのコンパイル
C言語ソースファイルのサフィックス名は「.c」、コンパイル後のファイルのサフィックス名は「. obj"。接続後 実行ファイルの拡張子は「.exe」です。
C 言語でプログラムを作成する手順:
- 編集: C プログラムのソース コードを作成および変更することです。作成したプログラムはソースと呼ばれます。コード。
- コンパイル: ソースコードを機械語に変換することです。コンパイラの出力がオブジェクトコードとなり、それを格納したファイルをオブジェクトファイルと呼びます。拡張子は .o または .obj です。 (コンパイルのこの部分は、アセンブリ言語をコンパイルするアセンブラー、または高級言語をコンパイルするコンパイラーを指します)
- リンク: リンカーは、コンパイラーによって生成されたさまざまなモジュールからのソース コードを結合し、 C言語が提供するプログラムライブラリに必要なコードモジュールを追加し、実行ファイル化します。 Windows では拡張子は .exe ですが、Unix では拡張子がありません。
#実行: プログラムを実行します。 C 言語ソース プログラムが C 言語コンパイラによってコンパイルされると、接尾辞「.OBJ」が付いたバイナリ ファイル (オブジェクト ファイルと呼ばれます) が生成され、最終的にバイナリ ファイルが生成されます。 「接続ファイル」と呼ばれるファイルが生成され、「プログラム」(リンク)ソフトは、この「.OBJ」ファイルとC言語が提供する各種ライブラリ関数を接続し、拡張子「.EXE」の実行ファイルを生成します。当然のことですが、C言語はすぐには実行できません。
プロセス図は次のとおりです。
図からわかるように、コードのコンパイル プロセス全体は、コンパイルとリンクの 2 つのプロセスに分かれています。 . コンパイルは図の中括弧で囲まれた部分に相当し、残りはリンク処理となります。
コンパイル プロセス
コンパイル プロセスは、
コンパイル: コンパイルとは、ソース プログラム (文字ストリーム) を読み取り、字句的および文法的に分析し、高級言語の命令を関数に変換することです。アセンブリ コードと同様に、ソース ファイルのコンパイル プロセスは 2 つの主要な段階で構成されます。
最初の段階は前処理段階
で、正式なコンパイル段階の前に発生します。前処理フェーズでは、ファイル内に配置された前処理ディレクティブに基づいてソース ファイルの内容が変更されます。たとえば、#include ディレクティブは、ヘッダー ファイルの内容を .cpp ファイルに追加する前処理ディレクティブです。コンパイル前にソース ファイルを変更するこの方法では、さまざまなコンピューターやオペレーティング システム環境の制約に適応するための優れた柔軟性が得られます。使用可能なハードウェアまたはオペレーティング システムが異なるため、ある環境に必要なコードは別の環境に必要なコードと異なる場合があります。多くの場合、異なる環境用のコードを同じファイルに配置し、前処理フェーズでコードを変更して現在の環境に適合させることができます。 主に次の側面を扱います:
-
#define a b などのマクロ定義命令
- この種の疑似命令の場合、プリコンパイルで必要なのは、プログラム内のすべての a を b に置き換えることだけですが、文字列定数としての a は置き換えられません。 #undef もあります。これは、特定のマクロの定義をキャンセルして、今後出現する文字列が置換されないようにするものです。
-
#ifdef、#ifndef、#else、#elif、#endif などの条件付きコンパイル命令。
- これらの疑似命令の導入により、プログラマはさまざまなマクロを定義することによって、コンパイラでどのコードを処理するかを決定できるようになります。プリコンパイラーは、関連ファイルに基づいて不要なコードをフィルターで除外します。
-
ヘッダー ファイルには、#include 'FileName' や #include などの命令が含まれています。
- ヘッダー ファイルでは、疑似命令 #define は通常、多数のマクロ (最も一般的なものは文字定数) を定義するために使用され、さまざまな外部シンボルの宣言も含まれます。ヘッダー ファイルを使用する主な目的は、特定の定義を複数の異なる C ソース プログラムで利用できるようにすることです。これらの定義を使用する必要がある C ソース プログラムでは、#include ステートメントを追加するだけで済み、このファイル内でこれらの定義を繰り返す必要がないためです。プリコンパイラーは、ヘッダー ファイル内のすべての定義を、コンパイラーによる処理のために生成する出力ファイルに追加します。 Cソースプログラムに含まれるヘッダファイルはシステムが提供することができ、通常は/usr/includeディレクトリに配置されます。山かっこ () を使用してプログラムに #include します。さらに、開発者は独自のヘッダー ファイルを定義することもできます。これらのファイルは通常、C ソース プログラムと同じディレクトリに配置されます。この場合、#include では二重引用符 ('') を使用する必要があります。
-
特殊記号、プリコンパイラーはいくつかの特殊記号を認識できます
- たとえば、ソースプログラム中に表示される LINE ロゴは現在の行番号 (10 進数) として解釈され、FILE は現在コンパイルされている C ソースプログラムの名前として解釈されます。プリコンパイラは、ソース プログラム内のこれらの文字列の出現を適切な値に置き換えます。
プリコンパイラが行うことは、基本的にはソース プログラムを「置き換える」ことです。この置換の後、マクロ定義、条件付きコンパイル命令、特殊シンボルを含まない出力ファイルが生成されます。このファイルの意味はプリプロセス前のソースファイルと同じですが、内容が異なります。次に、この出力ファイルはコンパイラの出力として機械語命令に変換されます。
コンパイルおよび最適化段階の第 2 段階、プリコンパイル後に取得された出力ファイルには、数値、文字列、変数定義、および定数などの定数のみが含まれます。 C 言語のキーワード (main、if、else、for、while、{,}、,-、*、\ など)。
- コンパイラが行う必要があるのは、字句解析と構文解析を使用して、すべての命令が文法規則に準拠していることを確認し、それらを同等の中間コード表現またはアセンブリ コードに変換することです。
- 最適化処理はコンパイルシステムの中でも比較的難しい技術です。これに伴う問題は、コンパイル テクノロジ自体に関連するだけでなく、マシンのハードウェア環境にも大きく関係します。最適化の一環として、中間コードの最適化が行われます。この最適化は特定のコンピューターには依存しません。別の種類の最適化は、主にターゲット コードの生成を目的としています。
- 前者の最適化では、パブリック式の削除、ループの最適化(コード抽出、強度の弱化、ループ制御条件の変更、既知量のマージなど)、コピー伝播、無駄な代入の削除が主な作業となります。 、など。
- 後者のタイプの最適化は、マシンのハードウェア構造と密接に関係しており、最も重要なことは、マシンの各ハードウェア レジスタに格納されている関連変数の値を最大限に活用する方法を検討することです。メモリアクセスの回数を減らすためです。また、マシンのハードウェア実行命令(パイプライン、RISC、CISC、VLIWなど)の特性に応じて、命令をどのように調整してターゲットコードを短くし、実行効率を高めるかも重要です。研究テーマ。
アセンブリ: アセンブリとは、実際には、アセンブリ言語コードをターゲットの機械命令に変換するプロセスを指します。翻訳システムによって処理される各 C 言語ソース プログラムは、この処理を通じて最終的に対応するターゲット ファイルが取得されます。ターゲットファイルに格納されるのは、ソースプログラムに相当するターゲットの機械語コードです。オブジェクト ファイルはセグメントで構成されます。通常、オブジェクト ファイルには少なくとも 2 つのセクションがあります。
- コード セクション: このセクションには主にプログラム命令が含まれます。このセグメントは通常、読み取りおよび実行可能ですが、通常は書き込み可能ではありません。
- データセグメント:主にプログラムで使用されるさまざまなグローバル変数や静的データが格納されます。一般に、データ セグメントは読み取り、書き込み、実行が可能です。
UNIX 環境には、主に 3 つのタイプのオブジェクト ファイルがあります。
- リロケータブル ファイル: 他のオブジェクト ファイルとリンクして実行可能ファイルまたは共有オブジェクト ファイルを作成するのに適したコードとデータが含まれています。
- 共有オブジェクト ファイル: このファイルには、2 つのコンテキストでのリンクに適したコードとデータが保存されます。 1 つ目は、リンカが他のリロケータブル ファイルや共有オブジェクト ファイルを使用して処理して別のオブジェクト ファイルを作成できること、2 つ目は、ダイナミック リンカが別の実行可能ファイルや他の共有オブジェクト ファイルを使用してそれを処理できることです。画像。
- 実行可能ファイル: オペレーティング システムによって作成されたプロセスによって実行できるファイルが含まれます。アセンブラが実際に生成するのは、最初のタイプのオブジェクト ファイルです。後者の 2 つは、それらを取得するために他の処理が必要であり、これはリンカの仕事です。
リンク処理:
アセンブラで生成されたオブジェクトファイルはすぐには実行できず、エラーが発生する可能性があります。多くの未解決の問題があります。
- たとえば、ソース ファイル内の関数は、別のソース ファイルで定義されたシンボル (変数や関数呼び出しなど) を参照する場合があります。プログラムは、特定のライブラリ ファイルなどの関数 を呼び出す場合があります。これらの問題はすべてリンカによって解決する必要があります。 リンカの主な仕事は、関連するターゲット ファイルを相互に接続することです。つまり、あるファイルで参照されているシンボルを別のファイルのシンボルの定義に接続して、これらすべてのターゲット ファイルがオペレーティング システムによってロードおよび実行できる統合された全体。
- 開発者が指定した同じライブラリ関数の異なるリンク方法に基づいて、リンク処理は 2 つのタイプに分類できます。
静的リンク: このリンクでは、メソッドの場合、関数のコードは、関数が配置されている静的リンク ライブラリから最終的な実行可能プログラムにコピーされます。このようにして、プログラムの実行時に、これらのコードがプロセスの仮想アドレス空間にロードされます。静的リンク ライブラリは実際にはオブジェクト ファイルのコレクションであり、各ファイルにはライブラリ内の 1 つまたは関連する関数のグループのコードが含まれています。
- ダイナミック リンク: この方法では、関数のコードはダイナミック リンク ライブラリまたは共有オブジェクトと呼ばれるオブジェクト ファイルに配置されます。このときリンカは、共有オブジェクトの名前とその他の少量の登録情報を最終的な実行可能プログラムに記録します。この実行可能ファイルが実行されると、ダイナミック リンク ライブラリの内容全体が、実行時に対応するプロセスの仮想アドレス空間にマップされます。ダイナミック リンカは、実行可能プログラムに記録されている情報に基づいて、対応する関数コードを見つけます。
- 実行可能ファイル内の関数呼び出しには、動的リンクまたは静的リンクを使用できます。動的リンクを使用すると、最終的な実行可能ファイルが短くなり、共有オブジェクトが複数のプロセスで使用される場合にメモリを節約できます。これは、この共有オブジェクトのコードのコピーを 1 つだけメモリに保存する必要があるためです。ただし、動的リンクの使用が静的リンクの使用よりも優れていることを必ずしも意味するわけではありません。場合によっては、動的リンクがパフォーマンスに悪影響を与える可能性があります。
関連する推奨事項: 「
C ビデオ チュートリアル
」
以上がC言語でソースファイルをコンパイルするとどのようなファイルが生成されますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。