読者の方からのメール

1999/06/28


私の書いた駄文、「C言語入門書」「先生と呼ばれるほどの…」に関連して、(ぱ)さんという方から有益なメールをいただきました。せっかく頂いたメールを私が読んだだけで終わりにしてしまうのは大変勿体無いと思い、(ぱ)さんに「自分のページで公開したいのですが」とお願いしたところ、こころよくお許しいただきました。そこで、早速メールのコーナーを作り、ここに掲載させていただきます。


私は、この業界の底辺にて細々とコーディングしている一介のプロ
グラマです。Lepton's worldは、毎週楽しみに読ませていただいて
おります。

「新・闘わないプログラマ」78, 84を読み、いくつか思うところが
あったので、メイルさせていただきました。

78の K西本批判は、その通りだと思います。実は私は、入社時の新
人研修でまさにこの本を使ったのですが、ANSI云々以前に、DOS依
存の部分が多くて閉口した記憶があります。

ただ、84を読んで少々引っかかったのは、K&Rは、果たして本当に
素晴らしいテキストなのだろうか、ということです。

K&Rにもウソは書いてあります。誤解を招く表現もあります。さす
がに、M田本やK西本のように、あきらかに著者がCの文法を知らな
いところからくるウソ、というわけではないですが、逆に、Cの、
文法上の「変なところ」を糊塗しようとするかのような記述がある
ように思います。

たとえば、p.148 より(以下ページ数は第2版訳改訂版によります)

  int *f();    /* f: intへのポインタを返す関数 */

  と

  int (*pf)(); /* pf: intを返す関数へのポインタ */

  は、この問題のいい例である。ここで * は前置演算子であり、
  ()より低い優先度を持つから、正しい結合を行なわせるにはカッ
  コが必要なのである。

でも、ここで出てくる * は、文法上演算子ではないですし、優先
順位も、演算子とは全く別のところで規定されています。

Cの宣言の構文は、「宣言と実際の使用を一致させるように作られ
ている」とのことですが、その(わけのわからない)規則のおかげで
多くのプログラマが混乱しています。

「なんで、宣言の中に*は出てくるのに、&を入れるとシンタックス
  エラーなのだろう? (おまけにC++だと別の意味になるし)」

「(char(*)[5])の、*を囲む括弧は、どう見ても無駄だから取っちゃっ
  てもいいよねえ?」

「演算子の間に突然登場するこのconstとやらは何やねん?」

# ポインタを後置演算子にすれば、だいぶ見易くなるとは思います
# が、それはまた別の話ではないかと思います。

本当に優れたCのテキストなら、これらの「素朴な疑問」にちゃん
と答えていなければならないと思いますが、K&Rは、この点につい
て、むしろ混乱を助長するような記述になっています。

ウソではない(?)けれど、さらにタチが悪い記述が、p.121にあります。

  関数定義の仮引数としては、

  char s[];

  および

  char *s;

  はまったく同一である。

この記述は、ウソではないかも知れません。確かに、関数定義の仮
引数の宣言なら、char s[] と char *s は同一の意味になります
(というか、コンパイラがここだけ特別にそう読み換えます)。
いったいこの右端のセミコロンは何だろう、というのは謎ですが。
ここだけ昔の Cなのでしょうか? :-p

でも、この前後の文脈からすれば、読者は、これが「関数定義の仮
引数の宣言においてのみ、コンパイラが特別扱いをする結果である」
という事実をまず確実に誤解します。おかげで、ローカル変数の定
義や構造体のメンバ定義に char s[]; と書いてコンパイラに怒ら
れたり、グローバルな char s[100]; を、extern char *s; で
externしようとして極めてタチの悪いバグに悩まされたりするわけ
です。

# 余談ですが、これを原書で見ると、「関数定義の仮引数としては」
# (As formal parameters in a function definitnion,)の部分の
# 直後に改ページが入っていたりしますね (^^;

さらにこの続きを読むと(p.121〜p.122)

  配列名が関数に渡されるときに、関数ではそれが配列として渡さ
  れたのかポインタとして渡されたのかを都合のよい方に判断して、
  それに応じて操作が行なわれる。

と書いてありますが、これではなんだか意味不明です。

真相は、

1)配列は、式の中では、(ごく少数の例外を除いて)即座に「その先
  頭要素を指すポインタ」に読み換えられる。
2)だから、関数の実引数に配列を入れれば、即刻ポインタに読み換
  えられているので、
3)関数に渡ってくるのははじめから常にポインタだ。

ということですよね。

そして、ウソでも間違いでもないですが、K&Rに登場するサンプル
コーディングは、ポインタ演算を濫用し過ぎです。もっとも、これ
については、「これこそがCらしいプログラムスタイルだ」と主張
する方もおられるかも知れませんが、私およびその周囲のような、
業界底辺のプログラマは大抵このような記述を嫌います。[]演算子
と添字による syntax sugarを使った方が読みやすいです。

そして、K&Rには、これまたタチの悪いことに、こんな記述があっ
たりします(p.119)

  ポインタを使う方が一般に高速であるが(以下略)

今時のコンパイラでは、これはやっぱりウソですよね。

K&Rでは、*p++だの、*++argv だのを使いまくっていますが、様々
なレベルの人と一緒に大規模なシステムの構築に携わっている身
としては、やっぱり今時こんなコーディングをして欲しくはない
なあ、と思うのです。

私なら、ポインタ演算するぐらいならさっさと添字を使いますし、
インクリメントはそれだけを1行で書きます。

「できんぼーず」を含むプロジェクトでは、多少冗長でも、このよ
うなスタイルを取っている所が多いと思います(Practical C
Programmingでも勧めてますし)。そういう意味で、私としては、今
後一緒に仕事をすることになるであろう新人君に、K&Rのサンプル
コードは見せたくありません。
# 昔のコードを読むためには、ポインタ演算も知らなければ困る、
# というのがちょっと悩ましいところではありますが。

その他、K&Rには、浮動小数点数を扱っているサンプルコードは一
箇所しかないですが、そこではやっぱりfloat使ってるとか、気に
なるところはまだまだあるのですが...

明確に「間違い」だと突っ込むにはちょっと、という所が多いので、
この辺にしておきます。

K&Rは、あ、ウソ書いてる、と思うと、次の文で補足してたりして、
確かに正確を期しているのでしょうが、初心者さんにとっては
「何が言いたいんだかわからん」となってしまう面があると思います。

>なにか、これはいい入門書だよ、という本は無いでしょうか? ご
>存知の方がいらっしゃったら教えて下さい。

これは私もつくづくそう思います。

いろいろK&Rの悪口も書きましたが、現時点では、一冊にまとまっ
たCの参考書としては、(規格書を除けば)K&Rが最も正確である、と
いうのは困ったものです。

C全体を通しての入門書ではないですが、ポインタ回りについては、

『秘伝C言語問答 ポインター編』  柴田望洋 著

が良いという話を聞きます。

私は、置いてあったのをぱらぱらめくった程度なのですが、第0章
の「テスト」で爆笑してしまいました。この本の著者は、確かに、
Cを理解しているようです。

ついでに、私も、こんなページを公開してたりもします。

配列とポインタの完全征覇
http://member.nifty.ne.jp/maebashi/programmer/pointer.html

タイトルからして偉そうです(^^;;

それでは、長々と失礼しました。

色々生意気言ってすみません。それでは。

要点は、「K&Rは、果たして本当に素晴らしいテキストなのだろうか」という所ですね。確かに、私もちょっと誉めすぎたかな、というところはあります。(ぱ)さんのメールでは、具体的にK&Rの変なところを指摘されていて、「確かにそのとおり」と納得のゆくところも多いです。もちろん、私の考えはちょっとちがう、と言うところもありますけど。
私もK&Rをテキストとして使って見て、納得の行かないところはいくつかありました。この間も書きましたが「第4章 関数とプログラム構造」の章は、話があちこちに飛んでいて、こんなん、どうやって体系的に教えるんだ、というようなところでしたし。それに、全体を通して言えるのは、図が極めて少なくて直感的に分かりづらい、例題のプログラムのアルゴリズムが難しすぎる、(ぱ)さんのメールでも言及されていましたが「*p++」とか「*++argv」とかの記述を嬉しそうに(?)使っている、などというのもあります。
でもまあ、テキストとして使うには、現状では(将来も?)これ以上の本は無いようなので、これを使うのがベスト、と私は思っています。ただ、私はK&Rをテキストとして使う、とは言っても、あの本に書かれている内容をそのまましゃべっているわけじゃなくて、結局のところは単なるペースメーカーというか、どういった内容をどういった順番でどういったペースで説明して行くか、ということに使っているだけだったりします。

(ぱ)さんとは、その後、何度かメールのやりとりをしまして、C言語の仕様のいいかげんさ、というか、行き当たりばったりさ、というか、本質的な欠陥が問題を複雑にしているのではないか、というような話になっております。特に、宣言の構文のあたり。
それから、メールの中でも言及されている「配列とポインタの完全征覇」のページ、かなりの力作です。K&Rを読んだだけでは誤解しがちな項目に付いて的確な説明がなされていますので、たとえば「C言語FAQ」のページなどとともに、Cプログラマ(C++プログラマも)の方にお勧めいたします。

[Home] [戻る]


mailto:lepton@amy.hi-ho.ne.jp