時代遅れひとりFizzBuzz祭り、ここ暫く少し重めのFizzBuzzが続いたので、今回は軽めのネタでいこうと思う。でも普通のネタでは面白くないので少しばかりキワモノをば。まあ私はライトなキワモノ層の人だと最近気づいたので「意外とメジャー、でもちょっとばかり斜め下」なチョイスで。
という訳でGDBでFizzBuzzしてみようか。GNU Debugger、実にメジャーだ。ユーザ数は結構多いはずだ。「Unix環境でCやC++で開発している人」というステレオタイプ以外にも、組み込みLinuxの開発者だとか、Xcodeのデバッガを使っている人だとか*1、Visual Studioが苦手でMinGWを使っている人だとか*2。ちなみに最近の私はEmacs経由ではなくTUIでGDBを使っているVimユーザ。あれ便利だけど、手元のMinGWのGDBでは未サポートなんだよね。
処理系――というのも変だけど――はTDM-GCCのgdb 7.2。TUIは使えないけどFizzBuzzには不要なので構わない。悔しくなんてありません。
GDBは(GUIのラッパー経由で操作しているのでなければ)コマンドで操作するデバッガで、そのコマンド体系はちょっとしたスクリプトを作成できる程度にはプログラマブルなものだ。こういうミニ言語的な所は、ある意味Unixらしいというか何というか。
ただデバッグ対象となるプログラム無しでは若干の制限が発生するコマンドもある。その点を考慮した上でデバッグ対象プログラム無しでFizzBuzzしてみた。
#!/usr/bin/gdb --batch -x define fizzbuzz set $f = 0 if $arg0 % 3 == 0 echo Fizz set $f = 1 end if $arg0 % 5 == 0 echo Buzz set $f = 1 end if $f == 0 output $arg0 end echo \n end set $i = 1 while $i <= 100 fizzbuzz $i set $i += 1 end quit
ユーザ定義コマンドであるfizzbuzzの呼び出しと変数$iのインクリメントを分けているけど、実は「fizzbuzz $i++」と1行で書ける。書けるけど実行結果は正しくない。挙動から推測するに、どうもfizzbuzz内で引数($arg0)にアクセスする度に$iがインクリメントされているようだ。
この問題は、$arg0を別の変数に代入してその変数を参照するようにすれば解決できるようだ。
#!/usr/bin/gdb --batch -x define fizzbuzz set $n = $arg0, $f = 0 if $n % 3 == 0 echo Fizz set $f = 1 end if $n % 5 == 0 echo Buzz set $f = 1 end if $f == 0 output $n end echo \n end set $i = 1 while $i <= 100 fizzbuzz $i++ end quit
このコードでは「fizzbuzz $i++」と1行で書いても問題なく動作している。
ユーザ定義コマンドの引数の扱いについては、幾つかドキュメントをあたってみたものの公式な見解は得られていない。もしかしたらGDBのバージョンによって挙動が異なるのかもしれない。