第一章:「プログラム」の実際


要約


「プログラム」はどこにどういう形で入っているか

結論から言うと,プロセサ(コンピュータの中枢となる部品.CPU,MPU)が理解できるのは二進数の羅列にすぎない.マトモな人間には理解不能.

この数字の羅列はメモリのどこかに固まりで入っていて,それをプロセサが順順に,あるいはプログラムによっては飛び飛びに読みながら,「数値○○は□□という意味だから,ご指示の通り□□します.はい次の命令は?」という風に実行する.この数値列のことを機械語(マシン語)という.

ここで言う実行とは,メモリからのデータ読み出し,その逆のデータ読み出し,読み出したデータの演算,入力受け付け,出力,正負などの何らかの判定およびそれに応じたプログラムのジャンプなどなどである.

上で少し示したように,命令の数値は一種類の「実行」に対応する.それぞれの数字の意味をもう少し人間にわかるように書いたものをアセンブリ言語という(図).そして,このアセンブリ言語(テキストでかかれている)を機械語(数値のラレツ)に変換するプログラムがアセンブラという.

機械語をアセンブリ言語に直すプログラムも当然あって,それは逆アセンブラという.

なお,マトモな人がアセンブラをいじる機会はそう多くはないと思う.多分直接には一生使わない.下記にアセンブリ言語の例を示す.「;」以後はコメント.

       CODESEG

        public  strrchr
strrchr proc \
        uses edi, \
        string:ptr byte, \
        chr:byte

        mov     edi,[string]    ; di = string
        xor     eax,eax         ; al=null byte
        or      ecx,-1          ; cx = -1
repne   scasb                   ; find the null & count bytes
        inc     ecx             ; cx=-byte count (with null)
        neg     ecx             ; cx=+byte count (with null)
        dec     edi             ; di points to terminal null
        mov     al,chr          ; al=search byte
        std                     ; count 'down' on string this time
repne   scasb                   ; find that byte
        inc     edi             ; di points to byte which stopped scan

        cmp     [edi],al        ; see if we have a hit
        je      short returndi  ; yes, point to byte

        xor     eax,eax         ; no, return NULL
        jmp     short toend     ; do return sequence

returndi:
        mov     eax,edi         ; ax=pointer to byte

toend:
        cld

        ret                     ; _cdecl return

strrchr endp
        end

人間が理解できる言語

アセンブリ言語はあまりにプロセサに「近すぎ」て,最低限の機能しかもたず,人間がこれを手なづけるのは大変である.こういうハードウェアべったりの言語を低級言語という.

アセンブリ言語の利点は,プロセサなどのハードウェアの性能を極限まで引き出す高性能プログラムが書けることである.

しかし,こんなものでいつもプログラムしなければいけないとなったら大変だ.それに,アセンブリ言語はプロセサが変わったら全て書き直しという可能性がある.

プロセサは,製造会社が違えば機械語も全く違うのが普通.例外はIntel(Pentium,Celeron等)とAMD(Athlon,Duron等)で,これは機械語がだいたい共通.他のプロセサ(IBMのPowerPC,DEC(現Compaq)のAlpha,MIPSのMIPS,SUNのSPARC,HPのPA-RISC)は軒並み全て機械語が違うと考えてよい.どれかのプロセサで動く機械語コードは,他のプロセサでは全く意味を持たない数字の列となる.

そこで,人間が直接書くプログラムはもう少し「人間寄り」のもの,それも原理的にはどのプロセサでも同じソースコードで動くというものになった.これを高級言語という.

高級言語は,その性格から言って人間が理解できるテキストで書かれる.また,アセンブリ言語とは違ってプロセサを直接触らない.結局,プロセサからみると高級言語は全く理解できない文字のラレツとなる(プロセサは,自分の規約に沿った数値の羅列しか理解できないのだから).

というわけで高級言語でかかれたプログラムをコンピュータに実行させるにはいくつかの「手順」をたどり,プロセサにそのプログラムを「理解」させる必要がある.

代表的な手法として,コンパイラインタプリタとがある.


コンパイラとインタープリタ

人間がテキストで書いたオリジナルの文字列をソースコードあるいはオリジナルコード,または単にコードという.コードを書くことをコーディングという.プログラマの役目は,まずはこのコーディング.

コンパイラ:ソースコードを一気に対応する機械語に翻訳し,その「製品」を実行させる方法がまず一つ.この「翻訳」を行なうのがコンパイラ.コンパイラに対応した言語をコンパイル言語という.インタープリタに比べた特徴は,実行がとにかく速いこと.

インタープリタ:ソースコードを擬似的に「実行」するためのプログラムが別にあるスタイル.そのプログラムがソースコードを一行一行よみ,その意味を解釈しながら順次実行する.コンパイラに比べた利点は,「途中の好きなところで止める」「その止めたところでコンピュータの状態を検証する」といったデバグ作業が簡単であること,そして,コンパイルという作業が不要であるため書いたらすぐ実行というレスポンスの速い開発作業ができることである.

この講座では,コンパイル言語の代表としてFortran90とC,インタープリタの代表としてExcel VBAをとりあげる.

実はどの言語も,コンパイラにだけしか使えない(あるいはその逆)というわけではない.例えばWindowsのVisual Basicは,普段はインタープリタで実行するが,コンパイルして機械語コードにすることもできる. また,ここではとりあげないがデバッガというツールを用いてFortanやCをインタープリタ的に扱うこともできる.

なお,オリジナルのコードに対して,コンパイルされた機械語コードをバイナリコードという.


メモリとビット,バイト

コンピュータが数値やテキストや機械語プログラムを記憶しておくところを記憶域という.大きく分けてメモリストレージがある.

メモリは,電源を切ったら記憶している内容をすべて忘れてしまうRAM(randam access memory)とそうでないが書き換え自体ができないROM(read only memory)の二種類がある.昨今はメモリといえばRAMをさすのが普通(以後もそうする).メモリは,プロセサとの通信速度が速いのが特徴.実際のプログラム実行は,このメモリの上で行なう.一次記憶領域とも言う.

ストレージは,代表はHDD.電源を切っても内容が消えないし,書き換えも自由にできる.メモリに比べて単価も安い.ではなぜこのストレージの上でプログラムを実行しないか?というと,メモリに比べて極端にスピードが遅いのである.プログラム実行のたびにプロセサとストレージがいちいち交信しあっていると実用にならないくらいもたもたすることになる.大事なものをしまっておく物置のようなものだ.二次記憶とも言う.

メモリやストレージには,プログラムやデータ(テキストや画像やその他いろいろ)がはいる.基本的にはやはり二進数で入っている.

二進数一桁(0か1の値をとる)を1ビット(bit)という.1ビットは,2通りの状態を表現できる.2ビットは2の2乗=4通りの状態(00,01,10,11).ここで,表現を簡単にするために4ビットの2進数に一つの文字を割り当てる:

2進数(10進数で書くと)割り当てる文字
000000
000111
001022
001133
010044
010155
011066
011177
100088
100199
101010A
101111B
110012C
110113D
111014E
111115F

この「0」から「F」まで16種類の文字で,コンピュータに入っている数値情報を表すことがある.この表記法は16進数という.

例:コンピュータに「00101101001001010110101010110001」として入っているデータを16進数で表すと:2進数4ケタずつ0010/1101/0010/0101/0110/1010/1011/0001と区切って上の表と対照させると,「2D256AB1」となる.

さて,コンピュータでは8ビットというのが情報の単位として基本になる.これは16進数二桁に相当する.これを1バイト(byte)という.よくメガバイトとかギガバイトとかいう言葉を聞くかもしれない.ちなみにフロッピーディスク一枚で1.4MB.昔はこれが「大容量」だったが…

1バイト=8ビットは何通りの状態を表現できるか?2の8乗=256通りである.アルファベット大文字小文字と数字と各種記号をあわせてもせいぜい100種類もないので,1バイトあれば英語圏で用いられる全ての記号を表現できることになる.だから伝統的に1文字=1バイトとして扱われてきた.この文字と数値の割り当てに方式には主にASCIIとEBCDICの二通りがあって,後者は古風な大型マシンで使われることが多い.両者は全く互換性がないので変換が必要.我々が普通目にするのはASCIIだと思う.ASCIIでは文字「A」は16進数41,「Z」は5A,「a」は61,「z」は7A,「*」は2A,「0」は30…といった具合である.

日本語中国語となると1文字に2バイト必要である(2バイトは2の16乗=65,536通りの状態を表現できる).

イメージとして,メモリはカイコの繭棚のようなものだと思えばよい.広大な平面が細かい方眼で区切られていて,すべて数字でもってその場所を特定できる.各升目には1バイトの数値が入っていて,それは(もともとは8桁の二進数であるが)二桁の16進数で表す.


AGATASHI