第2回 命令とは何だ? 〜鉄腕アトムは命令されるのか?〜
長谷川裕行
2008/4/4
■命令は3種類だけ
さて、プログラミング言語によってさまざまな呼称があるけれども、要は基本的な
命令は、
a定義や制御など骨格部分を構成するための予約語
b具体的な処理を行う関数(プロシージャ)
c演算子
の3種類である、ということだ。
C言語の#includeなどのプリプロセッサ指令やC++のclass、private、friendなどの予約語はに属する。との違いは、処理機能がコンパイラやインタプリタという「変換プログラム」の内部に埋め込まれているか否か──という点である。その観点からいえば、AとBは本質的には同じ部類の命令だといえる。
ほとんどのプログラミング言語のソースコードは、英語をベースにした文法体系を持っている。これは「人間に理解できる言語」である。
とはいえ、「ソースコードなんてちんぷんかんぷん」という人は多いだろう。しかし、それでも“if(i < 1000)”が「もしもiの持っている値が1000より少なければ……」という意味であることは、なんとなくわかるのではないだろうか。
■難解な原因は「変数」にある
ソースコードがわかりにくいといわれるのは、英語が使われているからではない。英語を理解できてもソースコードに記述されている意味(内容)がわからない、という人は案外たくさんいる。多くの人が、プログラミング言語のソースをわかりにくいと感じる原因の1つは、実は「変数」という「どんな値でも(型による範囲はあるが)受け入れられる仮想的な存在」のせいである。
if (300 < 1000)
といった記述は、一定程度の学力さえあれば誰が見ても理解できる。が、300ではなくて代わりに「i」が用いられ、
if (i < 1000)
と記されていると、上の一文はとたんに「数値的な比較」から「仮の世界の話」になってしまうのだ。
数学理論は、この「仮の世界、概念の世界」によって成り立っている。プログラミングに数学的センスが必要だとよくいわれるのは、計算や演算といった実質的な処理のレベルではなく、『変数』という「仮の器」を正しく把握できるか──ということなのだ。
■変数って何だ?
先の「演算子」の項で、「3に5を足すと……」という例をあげて「値の置き場所」のお話をした。それこそが『変数』である。アセンブリ言語では、たとえばAXレジスタだったり、あるいはアドレス1000番地の値(アセンブリ言語では[1000]のように記述する)だったりするわけだが、高級言語では「NumItems」とか「intValue」などといった変数を用いる。ここでいう『変数』には、オブジェクトのプロパティに保持された値も含まれる。
通常、ソースコードで「3+5」といった直接的な計算式が記述されることはない[注19]。「8」という定数を用いれば済む話だ(記号定数にするべきだが)。
intNumber = intCount + 8;
のように変数を使ったコードとなるはずだ。この“intNumber”や“intCount”といった変数が、最終的にはAXレジスタや1000番地から始まる4バイトのメモリ領域に置
き換えられるのである。
今、「1000番地から始まる4バイト」と書いた。1000番地は単にアドレスの開始位置であって、これだけでは変数とはいえない。変数には『型』が必要だ。それが「4バイト」といった占有するバイト数である。変数の型については、次回に詳しくお話しよう。
[注18]プログラミングの入門書ではありうるが、それはあくまでわかりやすく説明するための例である。また、Cの#define指令で記号定数を定義する場合に、“#define _ _Lines100 * 30”のようにわざと計算式を記述し、その意味(たとえば「100行を30ページぶん」のように)を示す場合がある。 |
■意図の伝達と言葉の変換
人間の理解できるソースコードは、最終的にはCPUにしか理解できない機械語に変換される。この過程を詳しく説明していると、コンパイラ設計の話になってしまうので詳細は割愛する。
基本的には、コンパイラ内には各予約語に対する変換テーブルがあり、文字列による命令文を2進数のニモニックとオペランドに変換していくのだ。そして最終的に、OSによってメモリに読み込まれたとき、実アドレス(現在、プログラムが配置されている実際のアドレス)に置き換えられるよう準備をしたうえで、実行形式ファイルが生成される。
たとえば、
count = 100;
という代入命令は、CXレジスタ[注20]に整数100を保持させる命令かもしれないし、アドレス0x1000番地からの2バイトにアドレス0x2000番地に保持した値(整数100)をコピーする命令かもしれない。こういった具体的なふるまいは、処理系によって大きく異なる。同じC言語の処理系でも、どの場面でメモリを使いどの場面でレジスタを使うのかは異なっている。
C言語でいえば、唯一統一されているのが、関数に渡す引数をスタックに積む(配置する)という点だ。
PascalとC言語では、この引数をスタックに積む順序が逆になっている。WindowsのAPI (Application Programming Interfaceの略)はPascal形式で引数を積む。まぁ、API関数の呼び出し処理がすべてブラックボックス化した現在では、どっちでもいいことかもしれないが……。
[注18]CXレジスタは、繰り返し処理のカウンタ機能などを担うレジスタ。CPU内のレジスタには、書き込まれるデータの用途・役割によっていくつかの種類がある。AXレジスタは計算やメモリの書き換え、SIレジスタはソースインデックス──データ転送元のアドレスを格納、などである。 |
■命令とは意図の伝達
前回のテーマ「UI」は、プログラマがユーザに対して、また、ユーザがコンピュータに対して意図を伝えるために存在するものだった。
プログラミングで用いる「命令」は、プログラマがOSやCPUに対して意図を伝えるための機能だ。
それぞれ役割は異なるが、「意図の伝達」という側面から見れば共通点が多い。意図をうまく伝えること──これがプログラミングの基本なのである。
本連載は、ソフトバンククリエイティブ刊行の『C MAGAZINE』に掲載された記事を、同社の許可を得て転載するものです。 なお、 Webでの連載として転載するに当たり、若干表現を変更している点があります(例えば「本書は」としている部分は「本連載は」としていることや図版などの省略など)。その点ご了承ください。 |
@IT自分戦略研究所は2014年2月、@ITのフォーラムになりました。
現在ご覧いただいている記事は、既掲載記事をアーカイブ化したものです。新着記事は、 新しくなったトップページよりご覧ください。
これからも、@IT自分戦略研究所をよろしくお願いいたします。