【プログラミング】インタプリタ方式とコンパイラ方式の違い

今回は、プログラムを実行するときにどのような処理が内部で行われるのかについて解説していきます。

プログラムを書くだけではプログラムは動きません。機械語に翻訳しないとコンピュータは理解してくれません。プログラミング言語で書いたソースコードは人間は理解できますが、コンピュータは理解できません。コンピュータは0と1によって処理を行いますからね。

せっかくプログラミング言語を勉強してプログラムを組んだのに実行できなければ意味がありません。機械語に翻訳する方法も覚えなきゃいけないのか…というとそんなことはありません。

機械語に翻訳する作業は言語プロセッサというプログラムが行ってくれます。なので、ソースコードを書いた後に何か複雑な作業を行う必要はありません。

機械語に翻訳する方式が2つありまして、この記事のタイトルにもなっている「インタプリタ方式」と「コンパイラ方式」があります。今回はその2つの方式について解説していきます。

インタプリタ方式

こちらの方式では、ソースコードに書かれた命令を1つずつ取り出して、機械語に翻訳しながら実行します。「動作を確認しながら作っていく」場合には、こちらのインタプリタ方式の方が適しています。

この方式では、インタプリタという名前の言語プロセッサプログラムが逐次翻訳を行います。

作成途中のプログラムもその箇所まで実行できるというメリットがある一方で、実行速度は遅くなりやすいというデメリットがあります。

こちらの方式に当てはまるプログラミング言語は、以下の通りです。

インタプリタ方式
  • BASIC
  • PHP
  • Python
  • Ruby

など…

コンパイラ方式

ここからが今回のメインです。

こちらは、ソースコードを全て翻訳してしまってから、機械語のプログラムの作成を行う方式です。ソースファイルからプログラムの実行が可能になるまでの一連の流れのことをコンパイルと言います。

翻訳を行う時間はかかりますが、実行速度は速いです。「作成途中で確認のために動かす」といったことはできません。プログラムの終了後やコンパイル後にプログラムの修正は可能です。

大規模なシステムを構築する際に使う言語はコンパイラ方式のものが多いというイメージがあります。あくまでこれは個人的なものであり、プロに聞くと別の回答が返ってくるかもしれませんので悪しからず(笑)。

コンパイラ方式
  • C言語
  • Java
  • COBOL

など…

インタプリタ方式ではソースファイルがあればプログラムが実行できるのですが、コンパイラ方式では、プログラムのソースファイルだけではプログラムは実行できません。C言語であればオブジェクトファイルというものが必要であり、Javaであればクラスファイルというものが必要になります。

ここからは、ソースファイルからこれらのファイルが生成されてプログラムが実行にたどり着くまでの流れを解説していきます。

まずは全体の流れをざっくり理解しましょう。このブログ恒例の雑な図の登場です。

実行可能ファイルが完成すれば、あとは読み込むだけでプログラムが実行されます!

この一連の流れを実現させるために言語プロセッサと呼ばれるプログラムが必要であることは先程説明したかと思います。この言語プロセッサというのは、厳密にはコンパイラ・リンカ・ローダと呼ばれる3つのプログラムのことです。これら3つが連携することで初めてプログラムが実行できるわけです。

ソースコードから目的プログラムを作成する作業を担当するのがコンパイラです。先程出て来た「機械語に翻訳」というのは、この部分のことを指しています。目的プログラムから実行可能ファイルを作成する作業を行うのがリンカであり、実行可能ファイルを読み込む役割がローダです。

コンパイラ・リンカ・ローダについてもっと詳しく見ていきましょう。

コンパイラ

コンパイラの役割は、人間がプログラミング言語を用いて作ったソースファイルを、コンピュータが解読可能な機械語のファイルに翻訳することです。

この翻訳作業をもっと細かく分解すると、以下の4つに分かれます。

コンパイラ
  1. 字句解析
  2. 構文解析
  3. 意味解析
  4. 最適化

最適化が終了すると目的プログラムが生成されます。4つの作業ではどのような処理を行うのでしょうか。

字句解析

ソースコードに書かれているプログラムコードを、細かく分解します。この分解する単位のことをトークンと言います。例えば、「a = b + 10」という内容のコードがあれば、「a、=、b、+、10」という風に分解します。

構文解析

字句解析で分解したトークンを、プログラミング言語の構文規則に則って解析を行います。この解析の過程で、構文木を生成します。構文木については、また後日の記事で解説します。

意味解析

変数の型や文がプログラミング言語の仕様に沿っているかチェックを行います。

最適化

より良いプログラムコードを作成できないかどうかの検討を行います。処理効率を向上させることが目的です。

ここまでがコンパイラの役割です。続いて、目的プログラムから実行可能ファイルを生成する過程を担うリンカについて理解しましょう。

リンカ

目的プログラムから実行可能ファイルを生成する役割を担います。

自分で作成したプログラムの中には、あらかじめ用意されている関数などが利用されています。この関数群のことをライブラリ関数と言ったりします。

実際にプログラムを組むと分かるのですが、「画面に文字を表示させる」「キーボードから文字を読み込む」といった作業は頻繁に必要になります。そういう処理に対して毎回毎回自分で記述していくとキリがないので開発環境側で準備してくれているわけなんです。

開発環境側が準備してくれているライブラリの中から目的プログラムの中で使われているライブラリ関数を引っ張り出して、コンパイル対象のプログラムとくっつける作業を行うのがリンカです。

くっつける作業をリンクというのですが、このリンクの方法にも2つあります。

あらかじめリンクしておくことを静的リンキングといい、プログラムの実行時にリンクする方法を動的リンキングといいます。

ローダ

実行可能ファイル(ロードモジュール)を主記憶装置に読み込ませることをロードと呼び、これを担うのがローダです。

ローダに関しては特に解説する内容は…ありません(笑)。

例題

インタプリタ方式にとコンパイラ方式について理解できたところで、これら2つの方式についての理解度を問う問題が過去に出題されていますので、ここで1つ紹介しておきますね。(少し問題を加工しています)

例題

プログラムをインタプリタで実行する方法とコンパイルを行ってから実行する方法で比較を行いたい。次の条件で比較する時、およそ何行以上のプログラムであればコンパイラを行った方が処理時間(コンパイル時間も含む)が短くなるか。

【条件】
1.実行時間はプログラムの行数に比例する。
2.同じ100行のプログラムをインタプリタで実行すると0.2秒かかり、コンパイルしてから実行すると0.003秒かかる。
3.コンパイル時間は100秒当たり0.1秒である。
4.コンパイルを行う方式の場合、プログラムの行数に関係なく、常に0.15秒のオーバーヘッドがかかる。
5.上記1~4に示す以外に発生する時間はすべて無視してよい。


【選択肢】
ア.50
イ.75
ウ.125
エ.155

この問題の正解、分かりましたか?

自分で考えたい方はここで画面のスクロールを止めておいてください。分からなかった方やもう分かった人はスクロールしてください。

では解説を行います。

結論から言いますと、正解はです。

プログラムの行数をxとおきましょう。インタプリタを使った処理時間とコンパイルを行った場合の処理時間が同じ時間になるときのxの値を求めればいいので、

インタプリタを使った処理時間 = コンパイルを行った処理時間

が成り立つように式を作りましょう。

上の式が成り立つときのxの値が答えです。

手順1:プログラムの実行時間をそれぞれ求める。

条件2より、1行当たりの実行時間は、インタプリタの場合は[ 0.2 × (x / 100)]秒になります。コンパイルの場合は[0.003 × (x / 100)]秒になりますね。

手順2:コンパイルを行う場合のコンパイル時間を求める。

インタプリタ方式の場合はコンパイル時間は発生しませんので、コンパイルを使う場合のみ考慮します。条件3より、行数がxの場合のコンパイル時間は、[0.1 × (x / 100)]秒になります。

手順3:オーバーヘッドの時間を求める。

手順2と同様、これもコンパイル方式のみです。条件4より、こちらは行数に関係なく、0.15秒ですね。

手順4:手順1から手順3の中で出した秒数を使って式を立てる。

先程、「インタプリタを使った処理時間=コンパイルを行った処理時間」の式を立てました。そこに手順3までで出した秒数を当てはめていきましょう。

インタプリタを使った処理時間は、手順1で出した[0.2 × (x / 100)]秒のみです。

コンパイルを行う場合の処理時間は、手順1の実行時間と手順2のコンパイル時間と手順3のオーバーヘッドの時間をすべて足した時間が処理時間です。したがって、[0.003 × (x / 100)]秒 + [0.1 × (x / 100)]秒 + 0.15秒ですね。

最後に、式に当てはめましょう。

0.2 × (x / 100) = 0.003 × (x / 100) + 0.1 × (x / 100) + 0.15 … ①

①式を解けば、xの値が分かります。そして、そのxの値が今回の答えです。中学生の数学の知識があれば計算できますね。

計算すると、x = 154…くらいの数値になるので、最も近い選択肢はエです。したがって、正解はエというわけですね。


いかがだったでしょうか。インタプリタやコンパイルの意味を理解していれば、方程式を立てて解くだけです。中学生の数学の勉強の中で方程式や方程式を使った文章問題を解いてきたと思いますが、こういう試験にも応用が利きますので、数学を侮ってはいけません。

と言っても、この試験を受ける方は大半が高校生で方程式はマスターしている人が多いと思いますので、この試験で問われる数学の知識に関しては全く問題ないかと思います。

まとめ

今回は、プログラムを実行するまでの流れについて解説しました。

機械語翻訳にはインタプリタ方式とコンパイラ方式があります。インタプリタ方式は、プログラムを実行する中で翻訳を行い、コンパイラ方式は、プログラムを実行する前にコンパイルという作業を行ってから実行します。

コンパイラ方式にはコンパイラ・リンカ・ローダという3つのプログラムが必要です。プログラムを機械語に翻訳するコンパイラ、ライブラリ関数と目的プログラムをくっつけるリンカ、ロードモジュールを読み込むローダの3つによってプログラムの実行までをアシストします。


というわけで、今回はここで終わりです。

今回の記事は普段より少し長くなってしまいました。ブログを書いていると感じるのですが、解説をしやすい内容と解説をしにくい内容がありまして、解説しやすい内容の方が自分なりに小さく噛み砕いて説明がしやすいので長くなってしまいがちです(笑)。

今回の記事の中で何か参考になる情報があれば嬉しいです。

最後までお読みいただき、ありがとうございました。