プログラムが動くまで — 機械語への翻訳

中級の解説は準備中のため、中級の内容を表示しています。

概要 — まず全体をつかむ

初級では「ソースコードは機械語に翻訳されて初めて動く」「翻訳にはコンパイルとインタプリタがある」を見ました。中級では、翻訳のタイミングという軸で全体像を整理します。

詳細 — 1段階ずつ追う

これは何をする係?

どの言語も、最後にCPUが読むのは機械語です。違うのはいつ・どこで機械語に翻訳するかだけ。この「翻訳のタイミング」で、実行のしかたが大きく3タイプに分かれます。

登場人物メモ:

  • ※1 機械語 — CPUが直接実行できる、そのCPU専用の命令
  • ※2 バイトコード — 特定CPU向けではない「中間の命令」。VMが解釈する
  • ※3 仮想マシン(VM) — バイトコードを解釈して動かすソフト(例:JVM)
  • ※4 ビルド — ソースから、実行できる形(実行ファイル等)を作り出す一連の作業

翻訳の3つの道

アニメーション『翻訳のタイミング(コンパイル/インタプリタ/VM)』を開く
違いは「いつ機械語に翻訳するか」コンパイル型(C など)事前にまとめて翻訳→速い・環境に依存ソース人が書くコンパイラまとめて翻訳実行ファイル機械語(0と1)CPU直接実行インタプリタ型(Python など)実行時にその場で翻訳→手軽・やや遅いソース人が書くインタプリタ1行ずつ解釈しながら実行結果その場で動く第3の道:バイトコード+VM(Java/JVM)中間形式に翻訳→VMが解釈。両者の中間(そこそこ速く・環境をまたぎやすい)ソースコンパイラバイトコード中間の命令仮想マシン(VM)解釈して実行実行どのやり方でも、最後にCPUが読むのは機械語。違うのは「翻訳をいつ・どこで行うか」だけ。
  • コンパイル型(C など) — 実行の前にソース全体を機械語へ翻訳し、できた実行ファイルをCPUが直接動かす。翻訳済みなので速いが、翻訳結果が特定のCPU/OS向けになり環境に依存する
  • インタプリタ型(Python など) — 実行時にソースを1行ずつ解釈しながら動かす。すぐ試せて手軽だが、翻訳しながら走るぶんやや遅い
  • バイトコード+VM(Java/JVM) — まず環境に依らないバイトコードへ翻訳し、それを各環境のVMが解釈して動かす。両者の中間で、そこそこ速く・環境をまたぎやすい

速さと手軽さ・移植性はトレードオフで、翻訳をいつ済ませるかがそのまま性能と持ち運びやすさに効きます。

ビルド:ソースから実行できる形へ

コンパイルの中では、ソースが段階を追って機械語に近づきます。

  1. 字句解析 — 文字の並びを、意味のある最小の単位(トークン)に切り分ける
  2. 構文解析 — トークンの並びを、文法にそった構造(木)に組み立てる
  3. 中間表現 — 特定CPUに縛られない中間の形にする(最適化しやすい)
  4. 機械語の生成 — 対象のCPU向けの命令に落とす

この一連を含め、ソースから実行できる成果物を作る作業全体がビルドです。ライブラリの結合なども、ここで行われます。

⚠️ うまくいかないとき

  • 環境依存で動かない — 実行ファイルは特定のCPU命令セットとOSの決まりに合わせて作られる。相手のCPU/OSが違うとそのままでは動かない(だからOS別に配布物を分ける)
  • 依存の食い違い — 必要なライブラリやそのバージョンが実行先に無いと動かない
  • 翻訳の見落とし — インタプリタ型は文法エラーがその行に来て初めて表面化することがある
  • 最適化の副作用 — 速くするための最適化で、境界条件の挙動が変わってはまることがある

環境ごと丸ごと箱に詰めて「どこでも同じに動かす」発想はDockerへ。バージョン管理はGitで。

関連する知識

理解度チェック

そのまま解けます(成績は保存されません)。無料アカウントを作ると、学習の記録と進捗の山登りが始まります。

1. コンパイル型とインタプリタ型の、いちばんの違いは?

2. 同じソースでも、OSやCPUの種類が違うと実行ファイルをそのまま使えないのはなぜ?

3. Java(JVM)方式の実行のしかたとして正しいのはどれ?

4. コンパイルの中でソースが機械語へ近づく段階の順序として正しいのはどれ?

5. コンパイルの途中で「中間表現(IR)」を挟むおもな利点はどれ?

6. インタプリタ型の性質として本文に合うのはどれ?

7. 特定のCPU向けではない「中間の命令」で、VMが解釈して動かすものを何と呼ぶか、カタカナで答えてください。

8. ソースコードから、実行できる成果物(実行ファイル等)を作り出す一連の作業全体を何と呼ぶか、カタカナで答えてください。