2007/11/29 (木)
デバッグのやり方,ソースコードの読み方
デバッグのやり方,ソースコードの読み方
mixi だと読みにくすぎるので、http://ema.fsr.jp/20071129.html で読むことを推奨します。
こういうのって、本にはなかなか書いてないし、あっても高い。良い本とかあるのかなぁ。知らないだけ?覚えてないだけ?
最近、そういう話題が多いので書いてみる。わかりにくいとか、変なこと書いてるとか突っ込み入れてもらえたら嬉しいです。
コツとしては、ソースコードと「にらめっこ」にないこと。
- とにかく printf を入れてみる
- とにかく書き換えてみる
- とにかく実行してみる
とにかく、手を動かすことが大事。後、巻き戻せるように配慮しておく。 svn などを使うと revert できて安心(サーバにあるファイルに巻き戻せる)。
- Google 先生に教えを請う
- 友人に助けを求める
のも重要な手段。臨機応変に。とにかく悩んで、ソースコードとのにらめっこは非効率的。
プログラムってのは、右から左に受け流すもの
「入力 → 加工 → 出力」の組み合わせ。*1
ここで、「加工」の部分に目がいきがちなんだけど、「入力、出力」の部分から行くのが王道。 出発点とゴールが見えない山登りなんて無謀。
入力と出力を把握する
ドキュメントを読む(なかったり,間違ってたり)
ここで言う、入力出力とは、プログラム全体のものに限らず、関数や行単位のものも含む。
"a,b".split(',') // Ruby: 入力は "a,b"、出力は ["a","b"]
ドキュメントがあるなら、それで概念をつかむ。でもドキュメントなんて無かったり間違っていたりは日常茶飯事。
んでもって、テストを書けばなお良いんだけど、それはひとまず置いておきます。
printf
とりあえず、いろんな場所に変数の中身を出力するコードを仕込みまくるのが定石。
fprintf( stderr, "%d", hoge ); // C / C++
やrequire 'pp' # Ruby
pp hoge # 複雑なデータ構造なら pp が見やすい
warn hoge.inspect # 単純なものなら inspect で十分
warn hoge.class # ほかにも欲しい情報があれば、はき出せばいい
などとする。SEGMENTATION FAULT するのなら、デバッガを使っても良いしfprintf( stderr, "1" );
// ... 処理 ...
fprintf( stderr, "2" );
// ... 処理 ...
fprintf( stderr, "3" );
// ... 処理 ...
fprintf( stderr, "4" );
などとどこまで動いているか力業で確認するのも一つの方法。自分用のデバッグ出力関数を持っておくと良い。
Visual Studio ならウォッチやデバッガから値を覗くのも一つの手。もちろん、gcc で gdb 使っても良いんですが、敷居が若干高い。
どんな値が出るか?、予想通りか?、違うのならどの時点でおかしくなっているのか?
色々入れてみて,出力をみる
入力の形式が分かれば、入力を変化させることが出来るようになる。色々いじってみて、どんな出力が出るのか把握する。
これは、中の挙動を把握する際にも有効な手段。まずは、どのような形式で出力されるのか?を把握することが大事。
中の挙動を把握する
やっぱり printf
解析範囲の規模が大きくなってきたら、内部状態や、途中経過を知るために printf を入れるのが無難。
A → B → C → D
の要になっているのが普通なので、B や C を printf すればいい。
適切な変数名や、B や C にする部分が関数で適切な名前がついていたら、類推が可能になる。名前重要。
○○はどこに? - よく分からない関数、変数が出てきたとき
Linux などなら、grep を使う。Windows でも grep と名前のついた何かを入れておくと便利。
grep 検索文字列 検索対象ファイル名
などとして使う。grepの簡単な使い方 が詳しい。
ソースを切り出して、動作を確認する
コンパイラ言語だと面倒だけど、スクリプト言語ならだいたいインタラクティブなシェルがあるのでそれを活用する。
Ruby なら irb。Ubuntu などだと、
sudo aptitude install irb
として、別途インストールが必要なので注意。
irb(main):001:0> [1,2,3]
=> [1, 2, 3]
irb(main):002:0> [1,2,3].join(',')
=> "1,2,3"
の用に使う。printf の際に inspect しておくと、irb にコピペできて便利。
irb 無しでコードを書く事なんて考えたくない。
JavaScript なら jash や Firebug を使う。
C / C++ でも、テスト用の main を用意して、関数単位で動作確認するとデバッグやコード読みに便利。
デバッガ
デバッガというのは、プログラムの実行を途中で止めて(ブレイクポイント)中身を覗いたり、落ちた箇所を特定するツール。
使い方を覚える必要があるが、使えるようになると非常に便利。C / C++ 系では重宝する。
Ruby / JavaScript だと printf デバッグで事足りることが多い。
- References
- Ruby で debug する7つの方法
- grepの簡単な使い方
*1 イディオム/慣用表現、は経験以外で獲得し得ないもの。他人のコードを読むしかない。

