Duff's Device

非常に珍しい書き方をしたCのコードを見た。その名もDuff’s Device。


情報元は諸悪の根源は物理的Duff’s deviceという記事。
実はこのコードは、comp.lang.cがおおもとの、有名なC FAQ 日本語訳にも出てきているほど、有名なコードのようである。
本当のおおもとの文章はTom Duff on Duff’s Device
しらなかったぁ。
まず、このコード。

send(to, from, count)
register short *to, *from;
register count;
{
 do
 *to = *from++;
 while(–count>0);
}

ポインタtoがデータの出力先。I/Oレジスタと考えればいい。ここにデータを投げ込むことにより送信されると考えて欲しい。
こいつが、遅いから最適化、ループを減らしましょう、ということで、以下のコードが出来上がった。

send(to, from, count)
register short *to, *from;
register count;
{
 register n=(count+7)/8;
 switch(count%8){
  case 0: do{ *to = *from++;
  case 7: *to = *from++;
  case 6: *to = *from++;
  case 5: *to = *from++;
  case 4: *to = *from++;
  case 3: *to = *from++;
  case 2: *to = *from++;
  case 1: *to = *from++;
       } while(–n>0);
 }
}

一見、何やってるのかよくわからないコードではあるが、丁寧に読めばわかる。
8で割った回数ループを回して、余りの分処理をするなんて最適化、結構ありがちなんだけど、余りの分の処理のコードが面倒だからと、こうなったらしい。
簡単に説明する。
まず、ループの外側から、swich文で、ループの内側のcaseラベルに飛び込む。
caseの後ろのbreakを入れて無いのでどんどん下の処理を行いながら、余りの分の処理を済ませる。
最後のwhile文が来るのでdoを探して、ループ開始。
まぁいまどきのCPUと、それにあわせたコンパイラの最適化の元ではこのような最適化が有効なのかどうかという議論は置いておく。(僕の予想では、効果なんてほとんど無いと思う。)
一般的に、ループの途中から飛び出すのはあんまりお行儀が良くないとされている。
これは、その逆。ループの途中に外から飛び込むコード。
中に飛び込むコートって、gotoを使わないと書けないと思ってた。switchでも書けるのね。
だいたい、生まれてこの方、一度もループの中に飛び込むコードって書いたこと無いかもしれない。必要ないし。。。
ついでに、case文の後ろのbreakの議論も入った、非常に興味深いコードである。
いやぁ、まだまだC言語について知らないことっていっぱいあるのねぇ。

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください