[Book] プログラミング関連書籍のご紹介―C/C++&アセンブラ編 (ja)

今回は筆者が中学生でプログラマーデビューしてから就職するまでの間にスキルアップのために活用した書籍を紹介します。学生時代に使っていた言語がC、C++、x86アセンブラであったため、それらに関する書籍の紹介になることをご了承下さい。

なお、就職後に習得したJavaを初めとする言語の参考書籍については別のエントリにて紹介します。

1. C
筆者が本格的にプログラミングを始めた時(1991年)、最初に選んだ言語はCでした。その頃はANSI規格ができたばかりで、ほとんどのCコンパイラがANSI規格を完全には満たしていない時期でした。この頃の学習書「100万人のC言語」(上・下)もそんな時代のコンパイラ合わせて書かれたもので、細かな点ではANSI規格に沿っていないところもあるでしょう。それでも自分のプログラマーとしての礎を築くのに功のあった書籍であり、今でも古本として入手できるようでするので紹介します。
本書は上巻(Cと遊ぶ)と下巻(Cプログラムに挑戦!)に分かれていて、それぞれが当時の入門書1冊に近いボリュームであるため、書店で手に取ったとき、正直引きました。上巻より薄い入門書1冊をすでに挫折した身としては、果たして上下巻をやり遂げることができるのか、正直自信はありませんでした。それでも拾い読みしてくどいほど丁寧に説明しているのを目の当たりにして、意を決して購入しました。当時使っていたQuick Cを前提に書かれていたことも大きかったと思います。
全体的に説明は平易で、プログラミング未経験者でも読み進められるような配慮が見受けられました。C言語入門書のお決まりとしてポインタのところでつまづくと思いますが、著者もおそらく相当説明に苦労したと思われ、何度も読み返すとわかるようにはなります。何度繰り返してもポインタのところが分からない書籍も多い中では珍しい方ではないかと思います。そのかわり、ポインタそのものの説明が薄くなり、一応ポインタは使えるようになるけれど、応用的な使い方は他の書籍で学ぶ必要があります。そういった意味では文字通りの「入門書」であり、必ずその次のステップを踏む必要が出てきます。当時の入門書としては良く出来たほうだったと思いますし、ANSI/ISO規格との差異もそれほど大きくない(入門書レベルではそこまで厳密な違いは説明できない)ので、今でも使えないことはないかと思います。

入門書の後に取り組んだのが、K&Rこと「プログラミング言語C 第2版」です。本書は原著の明快な解説を翻訳が帳消しにしたことで悪名高く、確かに何を言っているのか分からない部分も散見されますが、それでも手元に置いておいて損はない1冊です(英語に堪能なら原著がお薦めです)。実は筆者の持っているものは表紙が緑色で、現在販売されている白色の表紙のものは同じ原著を訳者の石田晴久先生が全面的に役を見直た後のものです(表紙が変わったのちしばらくは「改訳」を示す帯が付いていたのを思い出します)。ただ、書店で拾い読みした限りではどこが変わったのか分からない程度で、おそらく小さな誤訳を大量に修正しただけと思われます。
よく勘違いされますが、第2版のK&RはCの仕様書ではありません(初版の頃はANSI規格制定前であり、規格がないためK&Rを基準とした)。ただし、Cを開発したリッチー博士とCの伝道師カーニハン博士の共著であるため内容に間違いはないと思って大丈夫です。
筆者はこの本を教科書として使ったことはなく(サンプルが邦書の入門書のサンプルより高度で敷居を高く感じたため)、むしろ解説の充実したリファレンスとして現在に至るまで活用しています。特に巻末の標準ライブラリまとめは非常に重宝していて、Cの標準ライブラリリファレンス本を別途購入したことがありません。

K&Rを教科書として使うのであれば、「プログラミング言語Cアンサーブック」を持っておくのも悪くありません。先にも少し触れましたが、K&Rのサンプルや練習問題は、邦書のC言語入門書のそれよりもレベルが高く、単なる構文のサンプルでなくより実用的で取り組みのしがいがあるものとはいえ、K&Rの敷居を高くしてしまっているのも否めません。それに対する「保険」として、「アンサーブック」を買っておく手はあるかと思います。
筆者はというと、一時期持っていた時期がありましたが、今は手放しています。これはK&Rをリファレンス的に使うことが多く、練習問題にまっすく向き合うことが少なかったためです。
「アンサーブック」の他にK&Rを読みこなすための副読本のようなものも出ていたような覚えがありますが、個人的にはお薦めしません。それよりは自分に合った入門書でCの要点を押さえてからK&Rに直接取り組んだ方がよいと考えます。

2. 8086機械語/アセンブラ
筆者が次に取り組んだのが8086(厳密には80386)のアセンブラでした。これから紹介する「はじめて読む8086」は、当時のMS-DOSに付属するコマンドだけで8086の機械語を体験できるお得な書籍です(1993年当時、国内で主流だったPC-9800用のMS-DOSからは既にアセンブラのMASM.EXEが除外され、別売となっていましたから、これの意味するところは大きいです)。
しかし本書の凄味は、当時からトリッキーなことで知られていた8086のアーキテクチャをまるで洗練されているかのように思わせるほどの、解説文・図表・サンプルコードのコンビネーションにあります。本書の解説はとても平易ですが話題そのものはハイレベルで、読み手は知らないうちに高度な技術を会得している、そういった類いの書籍です。この傾向は著者・蒲池さんの他の著作にも共通して言えることですが、本書はその中でも突出しています。
8086は今や秋葉原のジャンクショップで缶ジュース以下の値段で購入できるほど過去の存在となりました。しかし、x86系CPUの一癖ある命令セットやリトルエンディアンはすべて8086時代から引き継いだものです。80286までプログラマを苦しめたセグメントの64KB制限も、i386(80386)以降で撤廃されたものの、それはセグメントがなくなったのではなくセグメントの上限をCPUの限界値まで引き上げられるようになったからに他なりません。8086ではレジスタがそれぞれの役割を持っていましたが、i386以降はほぼ汎用レジスタで一本化されました。しかしレジスタの名称や数量は基本的に8086の流れを汲んでおり、アーキテクチャの進化の中でレジスタは追加されても、中核となるレジスタはやはり8086時代から引き継いだものです。そういった意味から8086のアーキテクチャを学ぶことは近道ではないにせよ決して無駄になることはなく、8086を学ぶのであれば本書を一押しします。

「はじめて読む8086」には続編があります。最初の続編はこれから紹介する「はじめて読むMASM」で、この2冊で8086の機械語/アセンブラ開発に必要な事柄が一通り学べるようになっています。両者とも互いを意識しながら書かれており、随所に相手方へのクロスリファレンスが散りばめられています。
本書が想定する開発環境はMASM 5.1で、これは筆者が本書を初めて手にした時点で既に旧バージョンとなっており、筆者が実際に使っていたのはMASM 6.0でした。
MASM 6.0ではアセンブラがMASM.EXEから多機能なML.EXEに置きかわったのをはじめ、それ以降の標準となる初期処理簡略化構文がサポートされたため、特にメモリ管理については本書を参照することなくアセンブラ任せにすることが出来たのです。
MASM 5.1ではMASM 6.0でサポートされた簡略化構文が使用できずメモリ管理(具体的にはセグメントサイズの設定を指す)を手動で行う必要があり、本書ではそれについて相当のページを割いて解説しています。もちろん、8086の命令セットやその具体的な使い方についても、前作の雰囲気そのままで解説しています。
現時点でも相応に有益な「はじめて読む8086」に比べ、想定する開発環境を初めとして内容の陳腐化は否めません。しかし、この後の続編ではCPU命令セットの具体的な使い方までは多くのページを割けていませんので、その点については参照する価値はあるものと思っています。

「はじめて読む8086」シリーズのさらなる続編は、i486をターゲットとした「はじめて読む486」とPentiumをターゲットになとした「はじめて読むPentiumマシン語入門編」です。これらはアセンブラの解説というよりもむしろCPUアーキテクチャの解説と言った方がふさわしい内容で、前作の「はじめて読むMASM」続編ではなく、「はじめて読む8086」の新たな続編と考えるのが妥当でしょう。内容は概ね8086のものをi486あるいはPentiumに合わせて大幅改訂したもので、シリーズ全体から感じられるわかりやすさは保っているものの、最初の「はじめて読む8086」で受けた時の感動は正直ありませんでした。8086とi486/Pentiumとでは、重点を置く場所が明らかに違い、また8086時代のようにすぐにアセンブラで試せる環境が減ってきていること、そして何よりアセンブラ自体の利用率が下がっていることが言えるかと思います。
それでもアセンブラを学ぶには訳があります。アセンブラで直接アセンブルするケースはほとんど見かけなくなりましたが、C/C++のソース上にアセンブラのコードを記述する「インラインアセンブラ」はまだ現役だからです。ここで挙げた続編だけではインラインアセンブラを書くまでのスキルは得られないかも知れません。しかし、既存のインラインアセンブラを読むことは出来るようになるはずで、それがいずれ書くことにも繋がるからです。

3. C++
Cとアセンブラを学んでとりあえずプログラムを組めるようになった筆者(1994年頃)は、次の目標としてC++を掲げました。といってもC++は当時まだ標準化にはほど遠い状態で、Visual C++ 1.0付属のC++チュートリアルで悪戦苦闘していました。
数年後、C++のANSI規格化が完了し、1998年にはANSI規格に準拠した「プログラミング言語C++」が発売されました。本書はC++の開発者ストロウストラップ博士自ら執筆したもので、C++の神髄が記されているどころか、博士がオブジェクト指向に関する方法論(というか博士の持論)まで展開するという、野心的というか趣旨を半分誤ったというか、やり過ぎ感を強く受ける対策になっています。そして幸か不幸か本書が筆者にとって事実上最初のC++解説本になったわけです。
正直なところ、さすがに全部は読み切れず、途中からK&R同様にリファレンスとして使い出したのですが、本は重くて大きいしページ数も多かったためリファレンスとしてもやはり使えず。ただ、後半のオブジェクト指向開発の方法論については(賛否あるにせよ)筆者としてはとても参考になりました。本書の後半におけるクラスの定義、すなわち、まずデータ型が存在し、それに対するすべての演算を定義したものを1つにまとめてクラスと呼ぶことは、Javaプログラマとなった現在でも常に忘れることなく心に持ち続けています(ゆえに、それに反するコーディングを強いられると筆者は途端に機嫌が悪くなります)。
この本、C++のバイブルではありますが、同時に取扱注意です。

C++最初の1冊として筆者がお薦めするのが次の「C++のからくり」です。筆者にとっては2冊目の書籍でしたが、解説は明快でテンポがいい。しかも他の書籍では結果だけ書いて流すところを、本書は「なぜそうなっているのか」まで説明してくれる。その説明もくどくなく、理解を深めるのに役立ちます。
C++の言語仕様はまさに化け物で、前述の「プログラミング言語C++」が重い・大きい・ページが多いの三重苦(?)となっていることからもうかがい知ることが出来るかと思います(かの本はさらに開発方法論にまで手を広げているので余計にそう感じます)。つまり、標準的なボリュームの書籍でC++の全容を語るのは無理なのです。そこで解説するC++の言語仕様を取捨選択する必要があるのですが、本書はそれにも成功していて、本書だけでもそれなりにプログラムは組めるようになるし、さらに上級の解説書にステップアップする際にも困らないように必要な解説は漏らさずやってくれています。
最後に、JavaプログラマだけどJNIでC/C++が必要になった、と言う方にもお薦めしたいです。挫折しない程度のボリュームがあなたを救います。

C++を極めたいのなら、今も昔も「C++プライマー」は外せないでしょう。著者のリップマンはその昔、ベル研究所でストロウストラップ博士の片腕だった人物であり、その後時を経てMicrosoftに入社しVisual C++のアーキテクトとして標準非準拠で悪評高かったMicrosoft C/C++コンパイラをANSI/ISOに標準準拠させた功労者でもあります。そして今なおMicrosoftにおいてC++とC++/CLIの開発をリードしています。いわばC++の申し子とも言える著者がC++のすべてを語ったのが本書です。
本書は構成上、一応チュートリアルから上級トピックまで順を追って解説していますが、やはりチュートリアル部分の敷居が少し高いように見受けられます(他の邦書が不必要に低いところからスタートしているためかも知れませんが)。どちらかというと他の入門書でC++を学び、本書のチュートリアルは復習として使うと良いでしょう。解説そのものは版によって毎回翻訳者が変わっているのでそれなりのぶれはありますが、「プログラミング言語C++」よりは取っつきやすいという印象を持っています。

ある程度C++を使えるようになったなら、「C++プライマー」で極めるという手もありますが、もう一つメイヤーズの「Effective C++」で良いC++コード・悪いC++コードを学ぶのも効果があります。「Effective C++」のテクニックを会得した後は、続編「More Effective C++」でさらに高度なテクニックを学ぶことが出来ます。
本書は「こうすべし」「こうしてはならない」といったテーマを開きないし数ページ以内で解説し、そのテーマを30数個集める形で構成されています。だいたいの場合、興味のあるテーマから読み進めることが出来、読後も印象に残りやすい編集になっているのが特色です。このアイデアを借用したジョシュア・ブロックによる「Effective Java」という書籍もあります。
筆者の印象に残っているところでは、「継承を想定したクラスのデストラクタはvirtual宣言すべし」というのがあって、理由は詳細まで説明しないが、結果として派生クラスのデストラクタ呼び出しで止まり、その先の基底クラスデストラクタ呼び出しが行われない、というものでした。伏せられた理由はv-tblの細かい実装の話が絡んできて恐ろしくハードルが高くなってしまうので、敢えて「とにかく言うとおりにしろ!」という結論に落ち着けたのだと思います。その点、読み手のレベルをある程度考慮して解説してくれていると言えます。

次も短いトピック形式の解説書ですが、1冊丸々バグ探しの問題集です。タイトル「C++プログラミングの落とし穴」にふさわしく、落とし穴を小さなものから厄介なものまでひたすら100個以上集めています。
正直なところ、本書は好き嫌いがはっきり出ると思います。嫌いな人は徹底的に嫌がるだろうし、好きな人にとってはたまらない1冊(かも)。ちなみに筆者は、バグ探しがあまり好きではありません。特に見つけた時初歩的なミスだった場合、思い切り凹むじゃないですか...
仕事などで嫌でもC++のコードを見続けなければいけない人にとっては、この本に出てくるレベルの話は見聞きしているか、あるいは体験済みかも知れません。しかし、入門書を卒業したばかりでそれほどプログラムを書いていない人にとっては、机上デバッグの良い練習になると思います。また、よくあるバグを通じてC++の言語仕様でトリッキーなところを再認識する副次的な効果も(場合によっては)得られるかも知れません。


さて、C++の父ストロウストラップ博士は語らせると長いようで、しかも内容が深い。それを体現したような書籍が少し前に出版されました。「C++の設計と進化」と題されたそれは、博士のC++に対する想いがこれでもかと言うほど詰まっています。博士がCにSimulaをマージするようにして組み合わせて作った「C with Classes」がやがてC++へと進化し、紆余曲折をへながらANSI/ISO規格化そして現代に至るまで、語り尽くします。当然技術的な話題(しかも超ハイレベル!)も混ざってきて、初心者はおろか中級者でも非常に苦労する内容となっています(苦労している人間には筆者も含まれます)。
原著はC++の誕生から現在までを博士が語り尽くしたものだったようですが、邦訳に合わせて博士が何と1章を新たに書き下ろし、C++の未来についても語ってくれています。「プログラミング言語C++」の後半部でもそうでしたが、博士は語らせると長い。ただ、第一線の研究者の独演会を数千円の書籍で読めるということを考えると、むしろお得なのかも知れません。
この本、「プログラミング言語C++」以上に取扱注意です。

そしてC++関連の締めくくりは、おそらくC++「最狂」の解説書であろう、「C++オブジェクトモデル」です。幸か不幸か現在は絶版になっていて(その内容からおそらく再版することもないでしょうが)、こちらは「C++プライマー」のリップマンが、C++の内部構造をこれでもかと言うくらい詳細に語ります。例えば本書が書かれた当時のC++は一旦Cに変換されてからCコンパイラによってコンパイルされるのですが、その時C++のクラスはCではどう表現されるのか(例えば、メンバー変数が構造体、具象メンバー関数が通常の関数で、仮想メンバー関数はv-tblにぶら下がったv-ptrによって指し示されて、ポリモーフィズムの時にv-ptrをたどって適切な仮想関数を呼び出す、といった感じの話)について詳細な説明をしています。何しろ、初期のC++コンパイラはかなりの部分を彼が作っていますから、その細かさと言ったら半端ではありません。その証拠に、筆者は高校生か大学生の時に本書を手に入れたと記憶していますが、いまだに最初の2章くらいから先に進んでいません。それほどの難易度です。
本書に書いてあることがすべて理解できるのならC++プログラミングで恐れるものなんて何もありません。