コンピューター:師匠と弟子の会話:コンピューターとは


弟子:「師匠、もう第2回を書くのですか?」
師匠:「そうなのだ。一つだけじゃ寂しいし、第1回を公開してから一晩で8カウントしかアクセスが無かったから、これなら勝手なことを発言していても大丈夫だと、自信も出たしな。それに、今まで俺のホームページは丁寧な言葉で書いていたが、こういう話し言葉で書くことがこんなに楽だとは思わなかったんだ。考えてみれば、会社のページはともかく、個人のページは別に見ていただこう、じゃなくて良いんだよな。別にお金をもらって作っているわけじゃないし。見たいやつが勝手に見ていれば良いんだ。」
弟子:「まあ確かにそうですね。でも誰も見てくれなかったら何のためにホームページを公開しているかわからなくなるじゃないですか。」
師匠:「それが世の中暇な人がいて、頼まなくてもみてくれるものなのだ。俺も暇になるとWEBサーフィンばかりしているしな。」
弟子:「今の時代、WEBサーフィン以上の情報入手手段は無いくらいに便利ですよね。」
師匠:「そうだ。でも内容の保証は俺のページも含めて無いからな。みる側がちゃんと判断基準を持っていないとだめなんだな。」
弟子:「早速話が余談に膨らんでいますが・・・」
師匠:「そうだった。今回はコンピューターのページらしく、コンピューターとは、という漠然とした題目としてみたんだ。」
弟子:「そういえば、コンピューターっていったい何なんでしょうね?」
師匠:「コンピューターの定義を話そうって言うんじゃないんだ。俺の専門はソフト開発だからな。ただ、プログラムを組むやつが文法ばかり気にして、肝心の”なぜ”そうするかを考えないやつが多いから、そういう話をしようと思うんだ。あらかじめ言っておくが、ハード屋さん的な立場からみられると俺の話はかなりいいかげんだと思うが、それは気にしないでソフト屋的な立場から話をするのだ。」
弟子:「で、どういう話なんですか?」
師匠:「おまえはプログラミングを覚えるべく、C言語などを勉強しているらしいが、どのへんが難しいと感じるかな?」
弟子:「そうですねぇ・・・やっぱりアドレスとかポインタとかが出てくると逃げ出したくなりますが・・・」
師匠:「そういうやつが多いんだよな。そういうやつに今回の話を聞かせたいんだ。アドレスとかポインタを文法的な面からばかり考えていると確かに難解だな。関数の説明でも、値渡しとかアドレス渡しとか良くわからん言葉が出てくるし。でも、アドレスもポインタもわからなくたってがんばればプログラムはかなり難しい物だって組めるんだ。」
弟子:「じゃあ勉強しなくてもいいのですか?」
師匠:「しなくてもそれなりのプログラムは組めるな。でもあっという間に自分の組める範囲に限界が見えてくる。おまけにそういう状態でプログラムを組むということはコンピューターをわからないでプログラムを組むということなんだ。」
弟子:「はぁ、ではコンピューターのどういうことをわかればいいのでしょう?」
師匠:「プログラムというのはコンピューターにいろいろな動作をお願いすることが基本だな。だからお願いする相手がどういうものかを理解しておくことが大事なんだ。コンピューターの中心的立場にいるのはなんだ?」
弟子:「CPUですか?ペンティアムとかセレロンとか・・・」
師匠:「そうだ。CPUだ。CPUを日本語で言うとどういうことだとかそういうことは俺は苦手だから無視するが、要するにCPUが処理を実際に実行していくやつなんだな。」
弟子:「師匠は工業化学専攻でしたよね。」
師匠:「そうだ。だからよく学校で教わるような、コンピューターの用語の定義とかはあまり知らないし、興味も無いんだな。まあそんなことはどうでも良くて、CPUはどうやって働いているか知っているか?」
弟子:「電気で動いているんでしょ?」
師匠:「そんなことはあたりまえだ。そういうことじゃなく、CPUはアドレス空間を持っていて、そこからデータを読み出して、何かを演算した結果をそこに格納していくんだ。CPUがやっていることはほとんどそれだけなんだな。アドレス空間とはCPUがアクセスできる倉庫みたいなもんで、どこをアクセスするかは番地で管理しているのだ。で、その番地のことをアドレスと言うんだな。要するにアドレス空間はCPUが扱える番地の範囲のようなものだ。まあ、言葉の定義は苦手だから間違えているかもしれないが、とにかく、CPUは自分の扱えるアドレス空間に対してデータを読み書きするのが仕事なんだな。」
弟子:「アドレス空間ってどのくらいあるんですか?」
師匠:「簡単に言うと、CPUが一度に扱えるビット数で表現できる範囲、という感じだな。8ビットCPUだったらゼロ番地から255番地まで。16ビットCPUだったらゼロ番地から65535番地まで、32ビットCPUだったらゼロ番地から・・・自分で計算してくれ。ただ、全部のCPUがそうともいえない。中には内部16ビット、外部32ビットとかいう中途半端なやつがいて、内部処理は16ビットなんだがアドレス空間は32ビットを扱えたりするやつもいたな。まあ、この辺はハード屋さんに聞いてくれ。」
弟子:「師匠もあまりよく知らないようですね?」
師匠:「うるさい!必要なことだけ知っていれば良いんだ。そもそも俺はコンピューターは趣味じゃないしな。まあそんなことはどうでもいい。で、CPUがどうやって仕事するかはわかったな。」
弟子:「アドレス空間に対してデータを読み書きするんですね。」
師匠:「そうだ。で、CPUは電源を入れたときに、まず何をするかを、アドレス空間中のROMエリアから読み取るんだ。BIOSとか言うやつだな。そこにはCPUが理解できるマシン語で、RAMをチェックしろ、とか、ハードディスクのどこを読み込んでOSを起動しろ、とかかかれている。マシン語といっても実際はROMに入っている単なるデータだ。要するに数値だな。CPUごとに数値に意味があって、ある数値の場合は足し算をしろ、とか取り決めがあり、それがマシン語なわけだ。」
弟子:「RAMやハードディスクはどうやってCPUが見に行くんですか?」
師匠:「RAMはアドレス空間にそのまま結びついているような感じだな。ハードディスクとか周辺装置はアドレス空間に制御回路へのマップがされていて、あるアドレスに値を書き込むと、その先にある制御装置、ハードディスクコントローラーとかがそれに応じて動いてくれるんだ。まあ、この辺もあまり自信はないが、とにかくそうやってCPUは各種の初期化やチェックを終え、OSというプログラムをハードディスク上から読み込み、その後はアドレス空間にマップされた入力機器からデータを読み込んで、それに応じた処理をして出力機器にデータを出していくわけだ。」
弟子:「ところで、CPUはどうやってプログラムを実行するのですか?」
師匠:「CPUはアドレス空間とのやり取りしかしないからな。プログラムも単純にアドレス空間に展開されて、そこからマシン語の命令を読み出し、それに応じた処理をし、次の命令を読み出し、処理し、とやっていくわけだ。」
弟子:「なるほど。では、scanf()でキー入力を受け取り、printf()で画面に出力、というプログラムだったら、scanf()がマシン語のあるアドレスから入力しろ、という命令になって、printf()がマシン語の画面につながったあるアドレスに出力しろ、という命令になって、それが順番にCPUに処理されるのですね。」
師匠:「そこまで単純じゃないんだ。そんなことしたら、scanf()という関数の中で、たとえばウインドウ上のプログラムだったりすると、今カレントなウインドウかどうかを判断したり、ファイルからリダイレクトされているかどうかなど判断しないとだめだし、printf()なんかもフォントはどうなのか、とか上にほかのウインドウがかぶさっていないか、などいろいろな処理をしないとだめになるだろ。そんな面倒だけど基本的な部分をやってくれるのがOSやウインドウシステムなんだ。つまり、プログラムはOSやウインドウシステムに依頼をして、そこから先は共通処理をしてもらうんだ。ウインドウシステムもプログラムの一つで、ウインドウ管理をOSとプログラムの間に立ってやってくれるんだな。で、OSはハードとプログラムの間で基本的なI/Oなどを実現してくれるんだ。いちいちプログラムを1つ作るたびにディスクや画面のことまで考えていたら大変だからな。」
弟子:「なるほど、じゃあ、scanf()やprintf()がOSに依頼して、処理を実現しているんですね。」
師匠:「C言語の場合は、関数とシステムコールがあって、関数はわれわれが自分で作るプログラムと同じで、単なるプログラムの組み合わせ。で、システムコールが実際にOSとやり取りをするんだ。scanf()やprintf()は関数で、内部でread()やwrite()などのシステムコールを呼び出して、それがOSに依頼しているんだな。」
弟子:「いろいろな階層があるんですね。」
師匠:「そうだな。でもいずれにしてもCPUは単純にアドレス空間とのやり取りしかしないからプログラムもそうやって動くんだ。ところで、おまえが苦手なポインタとアドレスだが、先ほどから出てきているCPUのアドレス空間、この番地がアドレスなんだな。ただ、毎回必ずCPUのアドレス空間と1:1に対応しているわけではないが、番地という意味には間違いは無い。要するにアドレスは格納場所だ。で、ポインタは格納場所を指すための変数なんだ。」
弟子:「たとえば、関数内で、int i;とか定義して、&iと書くと、iのアドレスになりますから、iはCPUアドレス空間上でどこか、という場所を意味するんですね。」
師匠:「そうだな。CPUアドレス空間じゃなくて、ある仮想位置からの相対位置の場合とかもあるけどな。ファイルをマップしたり、共有メモリをマップしたりするとそういうふうになることもある。まあ、とにかくアドレスは場所だ。で、アドレスを簡単に操作するためにポインタがあるんだ。アドレスを変数として記憶したり、移動したりするためにな。」
弟子:「先ほどのint i;で、iの場所を記憶するのに、int *p;として、p=&i;とやると、pはiの場所を指すことになるんですよね。」
師匠:「そうだ。ただそれだけなんだ。それを文法ばかり考えていると、宣言の方法なんかばかり気になって、肝心の意味を理解し忘れてしまうんだな。ちなみに、関数というのも単なるアドレスなんだ。CPUがプログラムのマシン語を順番に実行していき、途中で、どの番地に飛べ、と関数のアドレスに飛んでいくんだ。コンパイラがこの関数はこういう命令の集まりですよ、というのをアセンブラ言語に直し、アセンブラ言語というのはマシン語を英語に当てはめて人間が理解しやすくしたものなんだが、それをマシン語のオブジェクト形式にし、最後にリンカーが必要な関数をまとめたりして実行形式にするんだが、その過程で関数の命令の集まりなどが決められるんだ。で、実行するときはCPUが扱えるアドレス空間、たいていはRAM上に配置され、そのときに関数のアドレスが決まるわけだ。シングルタスクシングルユーザのOSでは実行するたびにだいたい同じ番地になるが、マルチタスクマルチユーザーのOSなどでは実行するたびに位置は変わるが、相対的な位置関係は変わらないから、CPUはそこにジャンプして命令を処理していくんだ。」
弟子:「じゃあ、CPUから見ればデータも命令も同じなんですね。」
師匠:「そりゃそうだ。単なるアドレス空間に配置された数値にすぎないわけだな。ただ、ここの場所はデータを保持するのに使おう、とか、ここは命令を入れておこう、とか決めて使っているだけなんだな。」
弟子:「なるほど。じゃあ要するにアドレスとポインタだけわかっていればいいくらいなものなんですね。」
師匠:「そうだな。まあ本当にそれだけでプログラムを作るんだったらアセンブラ言語でプログラムを組めばいいんだな。自分でデータ領域のアドレスを決めたり命令のジャンプ先を決めたりしながら。ただ、それだと結構手間がかかるし、おまけに最近の環境はマルチタスクで複雑だから自分で管理しないといけないことがあまりに多い。だから、便利な高級言語を便利なライブラリとともに使わないとそもそも安心できるプログラムが組めなくなってしまうんだな。だが、コンピュータの動きの基本をわかってそれらの便利なものを使うかどうかで本当に理解してプログラムを組んでいるかどうかに大きな差が出るんだ。」
弟子:「アドレスとポインタはコンピュータの基本的な動きに直結したものなんですね。」
師匠:「そうだ。だから大抵アドレスやポインタを駆使したプログラムの方が性能が良いんだな。言語側での変換などが減るからね。ただ、アドレスやポインタはその分どうにでも操作できてしまうから暴走にもつながりやすいんだ。きちんと確保したところを指して読み書きしている分にはいいのだが、いつのまにかぜんぜん違うところを指していたり、あるいは指す場所を決めないうちに書き込んだりすると、命令が入っているアドレスに書き込んでしまったりして、CPUがそこの命令を実行しようかと思うととんでもないことになってしまうんだ。幸い、マルチタスクOSでは、自分の使える境界を越えてのアクセスとかはちゃんとOSでチェックしていてOS自体まで暴走することは少ないんだけどね。」
弟子:「変数は初期化して使え、と言いますものね。」
師匠:「まあ、BASICなどの言語のようにそもそもアドレスやポインタを使わせなければ安全なことは間違えないが、その分性能を上げられなかったり、どうしてもアドレスでアクセスしないとできない内容が書けなかったりするからな。だからBASICにはマシン語命令を直接実行するような変な関数があったりしたもんな。C言語はある程度管理したプログラミングを要求されるが、その代わり自由度も高く、いろいろなプログラムが書けるんだ。もっとも腕の差も出やすい言語とも言えるがな。」
弟子:「腕の差を見せつけることができるようにがんばります。」
師匠:「まあ、あまり懲りすぎると他人が読めないプログラムになるから、ほどほどにな。構造体とかもはじめはとっつきにくいが、単純にデータをまとめて扱えるようにしただけだからな。とにかく基本はアドレスだ。格納場所ね。そこを指すことさえできれば読み書きはこっちのもんだ。昔は・・・昔話が多くなると俺も年を取った証拠だな。昔は直にVRAM空間に値を書き込んで画面に文字を出したり、色をつけたり、ビープ音のアドレスに値を書き込んで音を出したり、アドレスの意味も実験してわかる良い時代だったが、今ではじかにアドレス指定で書き込むことはOSに許されない場合がほとんどだから実験も難しいよな。せめて、自分のプログラム内の変数や関数のアドレスを表示してみたりして、実際にどのように配置されているかなどを検討してみて欲しいな。」
弟子:「わかりました。変数には&をつければアドレスになりますし、関数はそのままアドレスですから、printf()で%xとかで表示すれば番地が見れますよね。早速やってみます。」
師匠:「そうだ。実際にやってみることが大事なんだ。知っていることと、使えることには大きな差があり、本を読んだりして知ることまででとまっていると、いざ使おうと思ったときに、問題がたくさん出てきて大変な目にあうものだ。知ったら実験して使えるようになっておくことが大事だな。まあ、相手がわからないうちは手ごわく感じるが、わかってしまえばたいしたこと無いものだ。コンピューターの動きなんて単純なものだ。もっともその上で動いているプログラムを使いこなすことはまた別問題で、結構大変だったりもするけどな。今回もすっかり長くなってしまった。喉が渇いたからコーヒーでも飲むか・・・」
弟子:「ところで、師匠、仕事は・・・」
師匠:「そうだ、仕事が最近少ないんだった。困ったものだな。まあ仕事のスピードは誰にも負けないから大丈夫だ。だが、仕事を取ってくるのは本当に大変だな・・・。まあこの辺の業界の話はまた今度ゆっくり話そう。危険な話も多いしな。」


よろしければブログもご覧ください
ゴルフ練習場紹介サイト:ゴルフ練習場行脚録更新中!
ipv400022162 from 1998/3/4