プログラミングの「は・て・な」

第2回 命令とは何だ? 〜鉄腕アトムは命令されるのか?〜

長谷川裕行
2008/4/4

演算子という命令語

 演算子が命令だというと「?」な人もいるかもしれない。が、立派な演算命令である。制御命令や関数、プロシージャの呼び出しはソースレベルで、

printf(...) ── プリントせよ

のように「言語での命令形」に近い記述をするため、これが命令であることは感覚でわかる。が、

numItems = 300;

の「=」や、

if (count < 1000) {

の「<」が命令だというのは、イメージ的にとらえにくい。

 「=」は、C言語では代入演算子だが、Visual BasicではSet命令の省略形である。本来は、

Set ItemNumber = 300

と書くべきところ、「Set」命令を省略して「=」だけが生き残った形だ。単独で用いる「=」はIf文の条件式で用いる比較演算子で、等価を意味する。C言語では比較演算子の等価に「==」を用い、意味の違いが記号にも反映されている。

リンゴが3個あります……

 「+」「-」「*」「/」といういわゆる四則演算子は、もちろん「演算子の指示どおりに四則演算を行え」という命令である。

 われわれ人間は、簡単に「3に5を足す(加算する)と8になる」といったりするが、コンピュータにとって、この計算とその結果を具体化するのはたいへんなことだ。

 まず、「3に5を……というけれども、いったい3はどこにあるのだろう? 5はどこから持ってくるのだろう?」という疑問にぶちあたる。

 人間の場合、「3+5」程度なら暗算すら不要で、ほぼ自動的に「8」という答を出す。もっと大きな数字なら、頭の中で筆算やそろばんによる暗算を行うだろうが、いずれにせよ「まず3をこの箱に入れて……」などとは考えない。

 たとえば小学校低学年なら、リンゴが3個のイメージが浮かび、次いでそれに5個のリンゴをつけ足して……と考えるかもしれないが、それでも、そのリンゴがカゴに入っているのかお皿に盛られているのか、といったことまで意識したりはしないだろう。

 ところがコンピュータでは、「3という値をメモリ上の指定された場所に保存するのか、それともレジスタに保存するのか」を明確にしなければならない。

 たとえば、値の置き場所をAXレジスタとするなら「3+5」は、

MOV AX, 3
ADD AX, 5

といったアセンブリ言語で表現できる。減算や乗除算まで言及しているとキリがなくなるので割愛するが、とにかくコンピュータは、どんなに初歩的で単純な計算でも、値の置き場所を明示して「それをもとに計算せよ」という命令を発しなければならないのだ。

比較演算も命令である

 では、「==」や「<」、「>」、「!=」(VBでは<>)といった比較演算子は命令なのか? もちろん命令である。

 これらは、先述したようにifなどの条件判断のベースとなる「条件式」で用いられる。条件式とは「式を評価した結果によって、その後のふるまいを切り替える」ための命令文だ。

 「評価」とは、式に記述された処理を行った結果を参照し、なんらかの動作につなげる処理である。つまり、評価のためには「値」を返さなければならない。

if (count < 1000)

とあれば、変数countが1000より少ない場合には真、そうでなければ偽という評価結果を返す。

 アセンブリ言語レベルでは、レジスタから値を減算した結果ゼロフラグ(ZF)が立てば(1になれば)等価、先頭ビットが0なら負の値だから真(少ない)、先頭ビットが立っていれば正の値だから偽(多い)──といった判断のできる結果を生じる。比較演算子は、このような処理を「行え」という命令なのである。

CPUに「if(もし…)」はない

 ここでちょっと寄り道して、機械語レベルでの条件判断と分岐の手順を紹介しておこう。

 条件判断と分岐の代表命令は「if」だが、そのほかに順次判断のswitch(VBではSelect)、反復命令のfor、whileなどがある。反復が条件判断・分岐の特殊形だということはおわかりだろう(分岐先が処理のうしろではなく、先頭に戻る形となる)。

 さて、機械語には「if」に該当する命令はない。CPUは単に演算と制御を行う装置である。では、C言語などの高級言語に用いられている条件判断はどのように処理されるのか? 単に値を比較して、ラベルで指定した行にジャンプ(次に実行する位置を変更)するだけなのだ。

 値の比較にはcmp命令を使い、結果は先述したZFやCF(桁上がりフラグ)のON/OFFで判定できる。x86系CPUでは、IP(Instraction Pointer)という特殊なレジスタ[注18]が次に実行する命令のアドレスを保持している。ジャンプとは、この値を書き換える処理だ。

 MASMなどの一般的なアセンブラでは、プログラマが直接IPを書き換えることはできないので(可能なアセンブラもある)、jmp、je(jz)、jbe、jgeなどのジャンプ命令とラベル(命令行につけた名札)を使って移動先を指定することになる。

○単純ジャンプ
 ・jmp <ラベル>:無条件で処理行を移動する

○条件ジャンプ
 ・je <ラベル>:比較の結果、値が同じときに処理行を移動する
 ・jb <ラベル>:比較の結果、値が小さいときに処理行を移動する
 ・jg <ラベル>:比較の結果、値が大きいときに処理行を移動する
 ・jbe <ラベル>:比較の結果、値が小さいか同じときに処理行を移動する
 ・jge <ラベル>:比較の結果、値が大きいか同じときに処理行を移動する

 なお、je(Jump Equal)とjz(Jump Zero)は同じ意味である。先述したように、機械語で「値aとbが『等しい』」とは、「a-bの解が0である」ということで、jeもjzも減算命令の結果が0である場合(ZFがONの場合)にジャンプする。また、jg(Jump Greater)はja(Jump Above)としても同じ。

 List 1は、前回紹介したPC98シリーズ用直接コンソール出力の一部である。漢字コードの判定で高級言語のifに相当する処理を行っている。

List 1 アセンブリ言語による条件判断と分岐の例
; chk_kanji1
;     漢字コードの判定
chk_kanji1             macro
               local     check2, kanji, not_kanji, ck_exit
               cmp al, 81h ----------- ALレジスタの値と'81h'を比較
               jb check2 ----------- 小さければ'check2'へジャンプ
               cmp al, 9fh ----------- ALレジスタの値と'9fh'を比較
               jbe kanji ------------- 以下なら'kanji'へジャンプ

check2:     cmp al, 0e0h ---------- ALレジスタの値と'e0h'を比較
               jb not_kanji --------- 小さければ'not_kanji'へジャンプ
               cmp al, 0fch ---------- ALレジスタの値と'fch'を比較
               jg not_kanji --------- 大きければ'not_kanji'へジャンプ
kanji:        stc
               jmp ck_exit
not_kanji:   clc
ck_exit:
               endm

[注18]register。CPU内部で一時的にデータを格納するメモリ。演算のための値や演算結果、メモリ上のアドレスなどを保持する。

命令は3種類だけ

自分戦略研究所、フォーラム化のお知らせ

@IT自分戦略研究所は2014年2月、@ITのフォーラムになりました。

現在ご覧いただいている記事は、既掲載記事をアーカイブ化したものです。新着記事は、 新しくなったトップページよりご覧ください。

これからも、@IT自分戦略研究所をよろしくお願いいたします。