時代遅れひとりFizzBuzz祭り GDB(GNU Debugger)編

時代遅れひとりFizzBuzz祭り、ここ暫く少し重めのFizzBuzzが続いたので、今回は軽めのネタでいこうと思う。でも普通のネタでは面白くないので少しばかりキワモノをば。まあ私はライトなキワモノ層の人だと最近気づいたので「意外とメジャー、でもちょっとばかり斜め下」なチョイスで。

という訳でGDBFizzBuzzしてみようか。GNU Debugger、実にメジャーだ。ユーザ数は結構多いはずだ。「Unix環境でCやC++で開発している人」というステレオタイプ以外にも、組み込みLinuxの開発者だとか、Xcodeのデバッガを使っている人だとか*1Visual Studioが苦手でMinGWを使っている人だとか*2。ちなみに最近の私はEmacs経由ではなくTUIでGDBを使っているVimユーザ。あれ便利だけど、手元のMinGWGDBでは未サポートなんだよね。

処理系――というのも変だけど――はTDM-GCCgdb 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のバージョンによって挙動が異なるのかもしれない。

それにしてもGDBデバッグするのではなく、GDB上でデバッグプリントでスクリプトデバッグすることになるとは……。

*1:Xcodeのデバッガは内部でGDBを使っていたように記憶している。

*2:これは私か。