Mission0-1  私のプログラミング歴BASICで戯れる

 さて、今回PIC道場は“Cでブロック崩しを作ろう”編ですが、その前に、わたくしS嬢のプログラミング人生について触れておきたいと思います。
 私がコンピューターを本格的に(?)いじるようになったのは、高校1年の夏、家にPCが導入された頃からです。当時はPC-9800シリーズ全盛期、5インチフロッピー2台搭載型がメジャーでハードディスクは高嶺の花、8インチフロッピーなんてのもまだ残ってました。皆さん見たことありますか、8インチフロッピー。バイオC1よりもでかかったっすよ。
 このPC-98ですが、全マシンにROM-BASICが入っていました。いやでも絶対にBASICがついてくるんです。しかもご丁寧なことにマニュアル2冊付き。そして、スイッチを入れると、ある年代以上の人なら絶対に知っているメッセージ
How many files? (1-15)
が表示され、リターンキーを押すとN88BASICが立ち上がります。好奇心旺盛な私としては、ほとんど必然的にBASICをいじることになってしまいました。
 さて、このBASIC、これが触り始めると結構面白いんです。インタープリタなのでお手軽にプログラムを実行できるし、グラフィックが自由に使えるので絵を書くのも簡単。こうなるともうBASICの虜、付属のリファレンスマニュアルに書いてある参考プログラムや、本屋においてある雑誌などを見つつ、適当に(決して適切なではない)自己流プログラミングをしていました。といっても、お遊び程度ですが。
 多分どこの学校にも存在していたと思うのですが、私の通っていた高校でもご多分にもれずチビプログラマー達のグループがありました。私はむさい男子高校生の集団に混ざって、勉強もせずにパソコンの話ばかりしていました。紅一点です。わたくしS嬢は高校生の頃からぶいぶいいわせてたのよ、というのは冗談ですが、BASICなどをわざわざ、しかも趣味で使おうとなどというような女子高生は当時まれだったんです。だって、想像してみてください。ガングロ茶髪にルーズソックスの女子高生が、ケイタイで「あのさ〜、あのfor/nextのループがぁ〜、ちょっとぉ〜」とか言ってるの。変でしょう?
 話はそれましたが、現在のS嬢のプログラミングの基礎はこの頃に作られました。

師匠のつぶやき 「How many files?」ネタは少々古すぎ。「8インチフロッピー>バイオC1」ネタは座布団一枚!

Mission0-2 私のプログラミング歴PASCAL, Fortranとの出会い

 さて、師匠はBASICからアセンブラへと、プロフェッショナルなプログラマーへの道を邁進されたのですが、いかんせん何事も中途半端な私。学校の先生にもピアノの先生にも「やればもっとできるのに、やる気がない」といわれつづけた私です。と言うわけで、私のプログラミングは純粋BASICどまりでした。
 ところが、大学に入ってから、情報工学の授業で、衝撃的な出会いをしました。PASCALです。PASCALはプログラミング教育用に開発された言語なので、非常にコードが見やすいのです。BASICは”goto”という反則技が使えるので、最終的には、いわゆるスパゲッティプログラムになってしまい、後から見ても何を書いたのだかさっぱり判らないことが往々にしてあるのですが、その点PASCALは違います。とにかくきっちりしている。ということで、当時はPASCALアルゴリズム辞典も多く出回っていましたし、それらはどれも非常に見やすく、とにかく判りやすいのです。
 しかし、やはり何事にも中途半端な私。当時はやっていたTurbo-PASCALを少々使ってはいたものの、やはり慣れ親しんだBASICは捨てられず、PASCALアルゴリズム辞典を見つつ、それをBASICに書き直して遊んでいました。
 そして、次なる出会い。それは工学部には必須のFortranです。これはBASICを長年やってきた私には、そんなに難しいものではありませんでした。何しろ、BASICはFortranの教育用言語として作られたものですから。でも、特にFortranに魅力を感じたわけでもなかったので、授業の課題以外では使ったことがありません。
 以上が大学時代までの私のプログラミング歴です。広く浅く、私の性格を如実にあらわしています。

師匠のつぶやき Turbo Pascal とは懐かしいのぅ。一世を風靡した「禿げちゃびんパスカル氏」を思い出した。

Mission0-3 私のプログラミング歴お手軽にVisual basic, Perlでお仕事

 さて、大学院に進学した私は実験に忙しく、しばらくプログラミングからは遠ざかっていました。が、そうこうしているうちに、時代は移り変わってゲノムが大はやり。何の因果か、私もゲノムプロジェクトに携わることになってしまいました。当然プログラミングで情報を処理することが必要となってきます。
 時代はWindows一色。しかも、ゲノムとなると世界の大学が絡んでくるのでUNIXも必要です。しかし、どちらにしろN88BASICなど使えるわけもありません。さて、どうしたか?
 まず、Windows上では、簡単だけど結構使えることで有名なVisual basicを使うことにしました。それプラス、Linuxで処理するときにはインタープリタで会得しやすいPerlを選択。ここで、Cを選ばなかったところに、やはり私の性格が現れています。
 しかし、UNIX/Linuxを使う上で、C/C++はどうしてもはずせないものだと、さすがの私も感じるようになってきました。そこに師匠からの指令です。“Cを使ってブロック崩しを作るべし”と。
 こんないいかげんな経歴を持った私を、師匠はPIC道場のページでえらく誉めてくださっているのですが、しかし、本当に自分がプログラマー志向なのかは判りません。が、とにかくこの機にCを会得するべく、私は師匠にビシバシ鍛えられることとなったのでした。

Mission1-1 画面に文字を出力せよ女は黙ってgcc

 さて、ここからが本題、『ブロック崩し』です。
 が、一応プログラミング経験はあるとはいえ、そんなものをいきなりCで作れるはずがありません(BASICでなら作れるかもしれないですが、ってちょっと悔し紛れですか?師匠?)。そこで師匠からは、一つ一つこなしていけばいずれブロック崩しにたどり着くであろう、『課題』が送られてくることになりました。
 さて、今回の課題は、『画面に自分の名前を改行付きで20回出力せよ』です。さすがにC未経験の私でも、「forループをつかって、printfで名前を出力するのね」とアルゴリズムが頭に浮かびました。
 しかしです、コードは書けそうなのですが、どうやってコンパイルしたらいいのかわかりません。コンパイルに使うコマンドで私が知っているものと言えば、makeだけです。師匠からは『コンパイルは全てgcc -Wallですべし。曖昧なコーディングは許しません』との通達がありました。でも私には師匠が言わんとしていることが全く理解できません。だって、gccのことをまるで知らないんだものー。
 そこで、師匠にgccについて教えを乞いました。以下そのやり取りです。

S嬢:Cのことはちょっとならわかりますが、gccのことが全く判りません。もちろんどうやってコンパイルするかもわかりません。適切な教科書を紹介してください。
師匠:gccの教科書にいいものはありません。それはともかく、そもそもgccを利用できる環境にあるのかね?
S嬢:私のコンピュータはWin/Linuxのデュアルブートなので、KDEのKDevelopが使えます。
師匠:KDevelop?統合開発環境なぞもってのほかじゃ。エディターでコードを書いてシェルでコンパイル。これが基本です。とにかく、女は黙ってgcc。
S嬢:じじょ〜……(涙)。

 しかし、そんな私を哀れに思ったのか、師匠は以下のサンプルプログラムを送ってくださり、コンパイルのしかたを説明してくださいました。

#include <stdio.h>
int main(int argc, char **argv){
     printf(“S-jou\n”);
}
これをhello.cというファイル名でsaveし、
$ gcc -Wall hello.c
で実行ファイルa.outが表示されればOK。


 プログラム超初心者に戻った気分ですが、とにかくやってみないことには話になりません。と言うことで、行動開始です。

S嬢のつぶやき
  よもやこんなことになるとは、思ってもいませんでした。
 いままで、インタープリタと統合開発環境にまみれて生きてきたわたしが、シェルでコンパイルとは…。ミッション・インポシブルっすよ。
 すごく動揺しているんですが、しかし、それもこれも修行なんですね、師匠。そう思って、がんばってコーディングにはげみます。

師匠のつぶやき 統合開発環境は分子生物学で言えば「ばかちょんキット」じゃ。キットに頼りっぱなしでは、いつまで立っても独り立ちはできないし、後輩を指導することも不可能。自立せよ!
Mission1-2 画面に文字を出力せよLinuxに遊ばれる私

 さて、師匠にいわれたとおり、hello.cをつくり、

$gcc-Wall hello.c

をやりましたが、

bash: gcc-Wall: command not found

と怒られるばかりで、ぜんぜん実行ファイルができません。さてどうする、S嬢?
 私の常套手段、「困ったときはmanよねー」、ということで、

$man gcc

を読むことにしました。

名称
     gcc,     g++ - GNU プロジェクト C および C++ コンパイラ (gcc-2.95.3)
 .......(中略)........
      警告オプション
              -fsyntax-only -pedantic -pedantic-errors -w -W
              -Wall -Waggregate-return -Wcast-align -Wcast-qual
              -Wchar-subscript -Wcomment -Wconversion
              -Wenum-clash -Werror -Wformat -Wid-clash-len
              -Wimplicit -Wimplicit-int
              -Wimplicit-function-declaration -Winline
              -Wlong-long -Wmain -Wmissing-prototypes
              -Wmissing-declarations -Wnested-externs -Wno-import
              -Wparentheses -Wpointer-arith -Wredundant-decls
              -Wreturn-type -Wshadow -Wstrict-prototypes -Wswitch
              -Wtemplate-debugging -Wtraditional -Wtrigraphs
              -Wuninitialized -Wunused -Wwrite-strings
......................

ああ、-Wallってgccのオプションなのね。当然よね。だって”-”がついてるんだから。私って、頭悪いかも…。
 ともかく、気を取り直して

$gcc□-Wall hello.c

で、みごと初コンパイル成功。実行ファイルもできました。当たり前です。師匠に言われたままやったんですから。
 しかし、ここまでの道のりがこんなに長いなんて。まだプログラムの“プ”の字すら見えてないのに…。統合開発環境になれきった私には、こんなことすらままならなかったのです。だって、なにしろこれがVisual basicだったら、ここまでの作業は、メニューから“コンパイル後に実行”を選択するだけでできてしまうんですから。
 さて、このhello.cですが、若干の問題点があります。それは、こんなに短くて簡単なプログラムなのにもかかわらず、コンパイル時にわさわさと警告がでるのです。師匠は、私に試練を与えるために、わざと何か足りないプログラムを送ったに違いありません。それはともかくとして、実行ファイルa.outを実行してみます。

$./a.out
S-jou
$

 無事コンパイルされていることがわかりました。じゃあ、あの警告はなんだったの?
 それはおいおい謎解きをしていくとして、今は課題を進めることに専念しよう、と心に誓ったS嬢でした。


S嬢の推測1
 gcc -Wallの”-Wall”は”壁”だと思っていて、「鉄壁のコードをかくのね」となどと勝手に思っていたのですが、それは大きな間違いだったようです。
$info gcc
をよむと、-Wallは

-w, -Wno-import, -Wchar-subscript, -Wcomment, -Wformat, -Wimplicit-int, -Wimplicit-function-declaration, -Werror-implicit-function-declaration, -Wmultichar, -Wparentheses, -Wreturn-type, -Wswitch, -Wtrigraphs, -Wunused-function, -Wunused-label, -Wunused-parameter, -Wunused-variable, -Wunused-value, -Wunused, -Wuninitialized, -Wreorder, -Wunknown-pragmas

以上のオプションを全てを含むオプションだ、と記述してあるので、「だぶりゅおーる」と発音するのが正しいのだと思います。

師匠のつぶやき 「鉄壁」と来ましたか、こりゃオジサン一本取られましたなぁ。座布団三枚!

Mission1-3 画面に文字を出力せよ師匠の技をパクれ!

 師匠からはB.W.カーニハン/D.M.リッチー著『プログラミング言語C』(以下K&Rと略します)を教科書とするように、とのメールがあったので、早速、大学生協のコンピュータ書のコーナーに行きました。「大変古めかしい本で、いまどきとてもはやらない本です。でも、きっと大学生協になら、1冊くらいあるでしょう」という話だったので、C関連の本が置いてある書棚をくまなく探したのですが、ありません。あきらめて注文しようか、と思ったそのとき、20冊ほどK&Rが横積みされてあるのに気がつきました。きっと情報系の授業の教科書に指定されていたのでしょう。とにかく、購入。その他にも、いままでの経験からリファレンスマニュアルがあるととても便利だと判っていたので、日向俊二著『C/C++プログラミング辞典』を購入。そして、課題へ向かって邁進することにしました。
 早速リファレンスマニュアルでforループを調べました。ところが今までの言語とは、だいぶ趣きがちがうようです。
 例えば、ループを20回繰り返す場合、これがBASIC / Visual basicならば

for i =1 to 20
next i

となるところが、Cだと

for(i = 1; i <= 20; i++){
}

です。カッコ内のi++がインクリメントで、BASICのstep 1と同じ意味なのでしょう。
 Cは会得するのが大変な言語だ、ということは判っていたからさけていたのですが、まさかここまで違うとは…。
 が、とにもかくにも、やらないことには始まりません。私は課題を書き始めるべく教科書を読み進めました。ところが、読めば読むほど、理解できないことが山積みになっていきます。プロトタイプ宣言仮引数リンクなどなど、わけわかめです。しかも、師匠より送っていただいたサンプルプログラムには、わたしが見たことのない

int main(int argc, char **argv)

と言う記述がありました。このintはいったいなに?私が知っているのは、PASCALのbeginに相当するmainというものだけです。その前にintがついたらどうなるっていうの?さらに、そのカッコ内の“int argc, char **argv”はなに?これが仮引数と呼ばれる、書いておくと便利なものらしいのですが、どういうあたりがどのように便利なのか、大体”仮”って一体何なのか、さっぱり理解できません。あ”〜〜〜。
 しかしとにかくいいかげんな性格の私、ここはひとつ、全てを最初から判ろうとするのは無理、と目をつむって、サンプルプログラムを改変することによって、課題1を完成させることを目指すことにしました。そしてできた、記念すべき初(パクリ)Cプログラム、kadai1です。

1: #include <stdio.h>
2:
3: int main(int argc, char **argv){
4: int i;
5: for(i = 1; i <= 20; i++){
6:   printf(“%d S-jou\n”, i );
7:  }
8: }

 4行目で変数iの宣言、5〜7行目でforループ。その間の6行目にprintf文をはさみました。printf文には、名前の前に出力した回数を表示できるように”%d”というものを使いました。ここに、コンマの後の”i”の値が代入されて表示される、という仕組みになっているようです。そして、”S-jou”のあとの”\n”、これが今回の課題の改行にあたるコードです。
 これを-Wallオプションつきでコンパイルすると

kadai1.c: In function 'main':
kadai1.c:8:warning: control reached end of non-void function

となります。この警告はhello.cをコンパイルしたときと全く同じです。でも、実行プログラムはちゃんとできるし、実際、実行すると

1 S-jou
2 S-jou
.................
20 S-jou

ぜんぜん問題ないじゃないですか。ちゃんと20回”S-jou”が改行付きで表示されて、その前に出力回数もきちんと表示されています。
 しかし、師匠からのお達しで、gcc -Wallで警告が出なくなるようなコードに直さなければなりません。どうしよう(おろおろ)。そもそもfor/nextのループをgotoで抜ける女として有名だった私が、そんなきっちりしたコードをかけるんでしょうか…。


S嬢の推測2
 プロトタイプ宣言についてです。
 プロトタイプとは関数の使い方のことで、コードの1行目の
<stdio.h>
に通常使う関数のプロトタイプについて記述してあるようです。ちなみにこれはどうも「すたんだーどあいおー」と発音するようなんですが、どうなんですか、師匠。


Mission1-4 画面に文字を出力せよプログラム・ネヴァー・エンド?

 コードを直すためには、gccがコードのどこに文句をつけているのかを知る必要があります。そこで、ここは一発根性をいれて、警告をまじめに読むことにしました。
 kadai1.cのコンパイル時の警告を翻訳してみると“関数mainが8行目でnon-void functionでおわっているのがいけない”ということのようです。このnon-void functionの意味がいまいちわかりません。

void: 空虚な、空の

という意味ですが、しかし、どうも”void”はCの業界用語ではないか、と私の野生の勘が訴えています。そこで、“void”をK&Rの索引で調べました。すると、pp.37に”関数のうち値を返さないものをvoid型という”という記述がありました。さらに、”関数は必ず値を返す。値を返さないものを明示するためにvoidを使う”とあります。
 PASCALやVisual basicではメインルーチンに値を返すルーチンのことをfunction(関数)、値を返さないルーチンのことをprocedure(手続き)といいます。Cの場合、procedureにあたるものがなく、全てが関数で構成されているようです。そのために、もし値を返さない関数があった場合には、そのことを判るようにするために、voidを使う、というわけです。
 ここで、師匠のサンプルプログラムに戻りますが、3行目の

int main(int argc, char **argv)

のintはなんだ?、とさわいでいた私ですが、どうやらこれは関数の型を示しているようです。つまり、“関数mainはint型だ”と宣言しているということになりますよね。ということは、当然結果を返さなければなりません。そこで、さらにK&Rの『第一章 やさしい入門 1.7関数』(pp.30)をひもとくと、そこには“関数の値はreturnで返す。mainの場合、returnの値が0だと正常終了、それ以外だと異常終了だ”という記述がありました。
 さて、kadai1の警告の件ですが、つまり、mainはint型の関数だ、といっているのにもかかわらず、値を返さなかったことをgcc君はわざわざ警告してくれていた、と言うわけです(K&Rには省略可と書いてあったのに…)。さすが-Wallオプション付きのコンパイルはキビシイ。
 師匠は、これらのことを私に自分で学習させるために、わざわざreturn文を入れないプログラムを送ってきた、と言うわけです。さすがわが敬愛する師匠、教育者としても奥がふかいです。
 ということで、プログラムはkadai1-1へと進化をとげました。

 1: #include <stdio.h>
 2:
 3: int main(int argc, char **argv){
 4: int i;
 5:     for(i = 1; i <= 20; i++){
 6:         printf(“%d S-jou\n”, i );
 7:     }
 8: return(0);
 9: }

 これをgcc -Wallでコンパイルすると、なんと初の警告なしの終了です。快挙です。そして、実行すると、なんとなんと、画面に美しく整然と”S-jou”の文字が20個表示されました。なんの問題もありません。問題解決、Q.E.D.。曖昧ではないコード、kadai1-1の完成です。


S嬢のぼやき
 Cはmainまで”関数”なんですね。どこまでも徹底した言語です。
 ちなみに、mainはどこに値を返すのか?K&Rによれば、システムらしいです。
 さすが、Cで記述されただけあって、UNIX/LinuxとCはどこまでも切り離せない関係なんですね。夫唱婦随、美しいですね。


Mission1-4 画面に文字を出力せよ中身もさる事ながら見た目も大事!

 私は、満を持してkadai1-1を師匠に送りました。すると以下の答え。

ビルドに問題はないが、見た目に問題あり。
空けるところは常にあけて、常にインデンテーションを意識して書く。
その、インデンテーションであるが、2文字が基本。
内部でネストしてくると、タブでインデントした場合右側にシフトし次行にはみ出してしまう。
私はこれが大嫌いなので、タブの変わりに2ブロックつかうべし。

師匠からの回答は

  1: #include <stdio.h>
  2: 
  3: int main(int argc, char **argv){
  4: 
  5: int i;
  6:  for(i = 1; i <= 20; i++){  
  7:    printf(“%d S-jou\n”, i );
  8:  }
  9: return(0);
 10: }

ということでした。
 プログラミングとは、どこまでも奥のふかいものです。確かに、Visual basic/BASICやPerlで私が今までさんざん書き散らかしてきたコードは、右側にシフトしすぎてびよよ〜んとなっていたし、だいいち、見にくいことこの上なく、後で見たときに何が何やらわからないことが往々にしてありました。(それはインデントの問題ではなく、スパゲッティだから、と言う理由も大ですが…)そして、何より最大の問題点は、後から見て何を書いたのだか判らないので、プログラムのリサイクルができない、と言う点でした。
 優れたプログラマーになるには、言語とハードウェアをしっかりと理解して、きちんとしたコードを書くことが大切ですが、そのコードはきれいに記述しておかないと後で見たときにわからなくなり、とても困るということですね。
 文字を20行出力するだけで、こんなに大変なC。しかもまだまだ判らないことだらけです。これからいったいなにがおこることやら。本当に私はボールを動かせるようになるのでしょうか?!
 次回の課題は『コンソールに自分の名前を階段状に表示せよ』です。乞うご期待。


S嬢の強がり
 今回、こんなにかんたんなプログラムを組むだけで、かなりの知識が必要でした。が、まだまだ解決されていない問題が山積みです。これらを理解するべく、努力いたします。
 次回の課題、一見簡単そうなんですが、きっと何かまた落とし穴があるに違いありません。しかし、最終的な目標はボールを動かすことです。
 こうなったら意地でもボールを動かして見せますぜ、師匠。見ていてください。