フィンローダのあっぱれご意見番

第3回:CRが先か、LFが先か

初出: C MAGAZINE 1992年7月号
Updated: 1996-02-24

[1つ前] [1つ後] [一覧] [ホームページ]


実は私はNIFTY-Serveのプログラマーズフォー ラムというフォーラムのSYSOPである。このフォーラムだがいまいち盛り上が らないので大変なのだが、なぜか連載を見てC言語フォーラム(FC)にやってくる 人が多い所がすごい。いつも思うのだが、NIFTY-Serveではフォーラム名称がFで 始まるため、FC という名前が絶妙で絶対これ以外にはないという明快さをもって いる。当り前のようだが、ネーミングのセンスの勝利である。プログラマーは、 ネーミングをもっと重視すべきだ。わかりやすい名前、というのが全ての始まり なのだ。

余談だが、同様に名前が決定的にものを言うのは、パッケージソフトの名前で ある。性能が数倍優れているよりも、名前が明快な方がよく売れるのではないか。 ここで勘違いしてはならないのは、何をもって明快とするか、ということである。 覚えやすく、雰囲気ぴったりで、かといって自己満足的だったり、凝りすぎて嫌 みを感じさせることがない、そういう名前を付けるのは実に大変なことなのだ。 しかし、どうも ABC-123 のような感じのパッケージソフトが今も売られているい うのが、いまいち釈然としない。

話はC言語フォーラムに戻る。ここにはQ&Aの電子会議があって、回答好きな 人達(失礼)が競って回答しているが、私も希に仲間に加わったりする。主に初 心者への回答を狙うことにしている。なぜかというと、高度な質問だと答がわか らないからだが。

さて、私は回答の最後に練習問題を付ける癖がある。本当に練習問題のこともあ るが、実は私も分かっていなかったりするので、練習問題という名目にして逆に 質問していることもあるとはお釈迦様も御存じあるめえ。ちょっと前になるが、 摩化不思議な問題を書いた。その話も、元はといえば、ある人の質問から話が始 まったのである。最初から書くと長くなって頁に収まらないから、最後に私が出 した問題のみ引用してみよう。


あたる「腹へったな〜。ラーメンでも食っていこうか」

 (ラムとあたる、ラーメン屋に入る)

ラム 「うち、カレーの方がいいっちゃ。」
あたる「なぜそれを先に言わんのだ!」

 (ラムとあたる、ラーメン屋を出る)

  問題:ラムとあたるがラーメン屋に入ったのはなぜか? ※


問題もすごいが、一体どこがC言語に関係あるのだ? と思われるかもしれない。 元はちゃんとC言語の話だったのである。ここまで来ると流石にギャラリーの皆 さんも呆然としたらしく、この後、見事に皆目コメントが付かなかった。

例えば、あたるがラムもラーメンを食べると思ったから、という感じの答でいい かもしれない。ではなぜそう思ったのか。そうなると難しい問題である。え、ど こがC言語に関係あるのかわからない? いや実は関係ないのですが。いや、全 然無関係というのではなく、少しは関係あるのですが。余計わからない? それ は困りましたねえ…。

    *
いきなりC言語になる。

リスト1は、改行のコードの組を CR+LF に整形する処理のつもりである。


/* リスト1 */
/* 行末のコードの組をCR+LFに整形する */

#define LF 0x0a
#define CR 0x0d

void set_end_of_line(FILE *in_fp, FILE *out_fp)
{
    int c;

    while ((c = getc(in_fp)) != EOF) {
        if (c == CR) {
            /* 読みとばす */
        } else if (c == LF) {
            putc(CR, out_fp);
            putc(LF, out_fp);
        } else {
            putc(c, out_fp);
        }
    }
}

もっと 具体的に書けば、CRとLFの任意の組み合わせが現われたら、CR+LFの2バイトの文 字列に置き換える、という処理である。なぜこういう処理を必要なのか不思議に 思う人もいるかもしれないが、UNIXマシンからデータをDOSマシンに変換した時に、 うっかり行末がLFだけになっていたりすると重宝することがあるのだ。もっと実 際的なのは、NIFTY-Serveを使っている人なら体験的にわかると思うが、行末がCR だけのデータや、CR+CR+LFのデータが、たまにあるのである。CR+CR+LFという行 末には驚くかもしれないが、クリッピングサービスで某通信社の提供しているニ ュース速報がこの形式の行末になっていて、エディタで表示すると各行末に^Mと いう表示が付いて、うっとおしい。

CR+CR+LF の行末になっていると書いたが、以下の考察では、この順序であ ることがポイントになるので、頭に入れておいて欲しい。 仮にLF、CRの順序で比較すれば、

 CRが現われる ---> LFと比較するが、一致しない
                    CRと比較して一致する。
  LFが現われる ---> LFと比較して一致する。
このように3回の比較で処理が終了する。この場合は、先にCRと比較して、後か らLFと比較しても回数は変わらない。では、CR+CR+LF だとどうか。LF を先にチ ェックした場合は、
 読んだ文字    比較する文字
  ------------------------------
  CR            LF  一致しない
                CR  一致する
  CR            LF  一致しない
                CR  一致する
  LF            LF  一致する
で5回の比較となり、CR を先にチェックする場合は、
 読んだ文字    比較する文字
  ------------------------------
  CR            CR  一致する
  CR            CR  一致する
  LF            CR  一致しない
                LF  一致する
で4回の比較ですむのだ。

なお、NIFTY-Serve のデータライブラリに登録されているデータの中には、改行 コードがCRのみになっているものがたまにある。 このような行末と「CR+LF」という行末 が混じったデータの処理を書く場合にも、 CR、LFの順序で比較し たほうが比較の回数は少なくてすむ。

さて、ここで問題は、c を CR、LF の順序でチェックしているのはなぜか、とい うことである。ここまできたら、比較の順序の理屈は分かるだろう。データによ っては、必ずしもこれが最善になるとは限らないのだが、一応理屈を考えたとい う点では評価してもよいと思う。後は、実際にプログラムを走らせて、どの程度 差があるかを調べるとよい。おそらく、殆ど差がないのでがっかりするかもしれ ない。

「ラムとあたるがラーメン屋に入ったのはなぜか?」という問題に戻るとこうで ある。まず、あたるが最適な行動をすると仮定しておく。ならば、単純に考えれ ば、ラーメン屋に入る前にラーメンを食べるかどうか尋ねるのがセオリーである。 そうすれば、ラーメンを食べないのにラーメン屋に入ってしまうという無駄な行 動をしなくてすむからだ。しかし、あたるがラムに対してラーメンを食べること にまず同意するに違いない、という予想をした場合には、まず間違いないことを わざわざ確認する手間の方が無駄であるから、とりあえずラーメン屋に入ってし まった方が、トータルとしては能率的かもしれない。このように、状況によって どれが最適になるかわからない場合には、話はえらいややこしくなるのだ。

    *
このような姑息なオプティマイズは、近い将来、ダイナミックなオプティマイズ が実現すればプログラマーの責任から解放されることを信じたい。つまり、処理 中に頻度の高い一致を統計処理して、よく現われる文字を最初に比較するように、 プログラムが処理をしながら自分自身のコードを変えてしまえばよい。仮名漢字 変換処理の学習機能をイメージしてもらえばよい。これがあらゆるコードに作用 する。ちょっと怖い気もするが。

しかし、結局肝心なのは、プログラマーの心意気。少しでも工夫してやろう、と いう気構えである。調子に乗りすぎると、最適化はされたが訳のわからんプログ ラムになる危険もあるかもしれないが、とりあえず心意気が重要なのだ。これが なければ、プログラムはいくらでも堕落する。まあ動かないプログラムもよくあ る話だから、とりあえず動けばよい、というのも説得力があるには違いないのだ が。

 ※問題の答 あたるの腹がへっていたから


(C) 1992, 1996 Phinloda, All rights reserved
無断でこのページへのリンクを貼ることを承諾します。問い合わせは不要です。
内容は予告なく変更することがあります。