logo

C プログラムのコンパイル: 舞台裏

コンパイルは、C 言語のソース コードをマシンコードに変換するプロセスです。 C は中間レベルの言語であるため、プログラムをマシン上で実行できるように、C を実行可能コードに変換するコンパイラーが必要です。

C プログラムはコンパイル中に次のフェーズを経ます。



Cでのコンパイル処理

C でのコンパイル プロセス

C プログラムをコンパイルして実行するにはどうすればよいでしょうか?

C プログラムをコンパイルして実行するには、まずコンパイラとコード エディタが必要です。以下の例は、GCC コンパイラーを備えた Ubuntu マシンの例です。

ステップ 1: C ソース ファイルの作成

まずエディタを使用して C プログラムを作成し、ファイルを filename.c として保存します。



np.ユニーク
  $ vi filename.c>

簡単な hello world プログラムを作成して保存できます。

ステップ 2: GCC コンパイラーを使用してコンパイルする

filename.c ソース ファイルをコンパイルするには、ターミナルで次のコマンドを使用します。

  $ gcc filename.c –o filename>

多くの命令を GCC コンパイラーに渡して、次のようなさまざまなタスクを実行できます。



Javaのデフォルトパラメータ
  • オプション -Wall は、コンパイラのすべての警告メッセージを有効にします。より良いコードを生成するには、このオプションをお勧めします。
  • オプション -o は、出力ファイル名を指定するために使用されます。このオプションを使用しない場合、a.out という名前の出力ファイルが生成されます。

C プログラムにエラーがなければ、C プログラムの実行ファイルが生成されます。

ステップ 3: プログラムの実行

コンパイル後、実行可能ファイルが生成され、以下のコマンドを使用して生成された実行可能ファイルを実行します。

  $ ./filename>

プログラムが実行され、出力がターミナルに表示されます。

ラテックスでテーブルを作成する

コンパイルプロセスの内部では何が行われますか?

コンパイラは、C プログラムを実行可能ファイルに変換します。 C プログラムが実行可能ファイルになるには 4 つのフェーズがあります。

    前処理 コンパイル アセンブリ リンク

以下のコマンドを実行すると、実行可能ファイルとともに現在のディレクトリ内のすべての中間ファイルが取得されます。

  $gcc -Wall -save-temps filename.c –o filename>

次のスクリーンショットは、生成されたすべての中間ファイルを示しています。

中間ファイル

これらの中間ファイルに何が含まれているかを 1 つずつ見てみましょう。

1. 前処理

これは、ソース コードが渡される最初のフェーズです。このフェーズには以下が含まれます。

  • コメントの削除
  • マクロの拡張
  • 含まれているファイルの展開。
  • 条件付きコンパイル

前処理された出力は次の場所に保存されます。 ファイル名.i 。 filename.i の中身を見てみましょう: $vi ファイル名.i

上記の出力では、ソース ファイルには非常に多くの情報が詰め込まれていますが、最終的にコードは保持されます。

  • printf には add(a, b) ではなく a + b が含まれるようになりました。これはマクロが展開されたためです。
  • コメントは削除されます。
  • #include が欠落している代わりに、多くのコードが表示されます。したがって、ヘッダー ファイルは展開され、ソース ファイルに組み込まれています。

2. コンパイル

次のステップは、filename.i をコンパイルして、ファイルを生成することです。中間コンパイル済み出力ファイル ファイル名.s 。このファイルはアセンブリレベルの命令に含まれています。このファイルを使って見てみましょう $nano ファイル名.s ターミナルコマンド。

サンプルJavaScript

アセンブリコードファイル

スナップショットは、アセンブラが理解できるアセンブリ言語であることを示しています。

3. 組み立て

このフェーズでは、filename.s が入力として取得され、次のように変換されます。 ファイル名.o アセンブラによって。このファイルにはマシンレベルの命令が含まれています。このフェーズでは、既存のコードのみが機械語に変換され、printf() などの関数呼び出しは解決されません。を使用してこのファイルを表示してみましょう $vi ファイル名.o

ハスネクストJava

バイナリコード

4. リンクする

これは、関数呼び出しとその定義のリンクがすべて完了する最後のフェーズです。リンカは、これらすべての関数がどこに実装されているかを知っています。リンカは追加の作業も行い、プログラムの開始時と終了時に必要な追加のコードをプログラムに追加します。たとえば、コマンドライン引数を渡すなど、環境を設定するために必要なコードがあります。このタスクは次の方法で簡単に検証できます。 $size ファイル名.o そして $size ファイル名 。これらのコマンドを通じて、出力ファイルがオブジェクト ファイルから実行可能ファイルにどのように増加するかを知ることができます。これは、リンカがプログラムに余分なコードを追加するためです。

注記: GCC はデフォルトで動的リンクを行うため、上記のプログラムでは printf() が動的にリンクされます。静的リンクと動的リンクの詳細については、この記事、この記事、およびこの記事を参照してください。