ショートカット
ファシリテーター × あり方
コーディングの向こう側
Hello, ANOTHER world!
オブジェクト指向のはなし
プログラミングのはなし
C言語実力診断クイズ
eSkillBooks
プログラミングのはなし

デバッグコードを書く

ソフトウェアをリリースするときには、おそらく次のように願うでしょう。

  • バグはすべて取り除かれた状態であってほしい
  • もしバグが残っていても見つからないでほしい。または見つかったとしても大騒動にならないでほしい
  • 実行速度に関して、できるだけ効率良く動作してほしい

一方、ソフトウェア開発中は次のように願うでしょう。

  • バグは、できるだけ早い時期に見つけたい

これらは明らかに矛盾した願いであり、同時に満たすことは不可能です。そこで、ソフトウェアには2つのバージョンが必要になります。すなわち開発中のバージョンと、リリース用のバージョンです。同じような開発を2度する必要があるという意味ではありません。ソースコードをコンパイルするときに、どちらのバージョンの実行ファイルを生成するか選択できる仕組みを作るのです。

そのためには、条件付きコンパイルを用います。C/C++ 言語では #ifdef を使用します。すると、開発中バージョンにだけ積極的にバグを検出するアルゴリズムを付加することができます。次の例を見て下さい。

SAMPLE
CODE
typedef enum {
    MORNING,
    EVENING
} GreetingTime;

void Greet( GreetingTime Time )
{
    #ifdef DEBUG
        if ( ( Time != MORNING ) && ( Time != EVENING ) ) {
            // バグ検出!
            ;
        }
    #endif

    switch ( Time ) {

    case MORNING:
        cout << "Good morning!" << endl;
        break;

    case EVENING:
        cout << "Good evening!" << endl;
        break;
    }
}

関数 Greet はパラメータ Time で表された時間帯によって異なる挨拶をするためのものです。パラメータとして許された値は MORNING, EVENING のみです。したがって、これら以外の値がパラメータとして渡された場合は、呼び出し側のバグです。

このバグを、#ifdef〜#endif の部分で検出しています(これがデバッグコードです)。実際には、if 文の中にバグが検出されたことを知らせるようなコードを書きます。バグはなるべく早い時期に発見したいので、大袈裟に振る舞うようなコードを書きます。通常は画面にメッセージを表示して異常終了するようにすれば良いでしょう。

このデバッグコードはマクロ DEBUG が定義されているときにだけコンパイルされます。つまり開発期間中は DEBUG マクロを定義するようなパラメータをコンパイラに渡すようにし、リリース用の実行ファイルを作るときには DEBUG マクロを定義しないでコンパイルします。これには makefile を使えば簡単ですね(make ターゲットを2つ用意するか、makefile 自体をを2バージョン用意します)。

デバッグコードを書く目的は、プログラムが自分の予測の範囲内で正確に動作しているかどうかを確かめることです。もしプログラムが自分の予測の範囲外で動作しているとしたら、それは運良く動いているに過ぎないのであって、決して信頼できるソフトウェアとはよべません。

上の例では、関数 Greet が受け取れるパラメータの範囲が決まっているので、呼び出し側は Greet が受け取ることのできるパラメータを渡さなければなりません。そこで Greet が受け取ったパラメータは常に正常範囲内の値であると予測し、実際にその予測があっているかどうかを検証しているというわけです。

デバッグコードはリリース用コンパイル時には無視されるので、副作用のあるコードを書いてはいけません。つまり簡単に言うと、デバッグコードはあってもなくても動作結果が同じでなければなりません。もっと簡単に言うと、変数に代入してはいけません(ただしデバッグコードの中にローカルスコープを作ってそこで宣言した変数に代入するのはかまいません)。現在の状況を検査し、それが予測の範囲外であった場合に知らせるというのが基本です。

また、デバッグコード中では実行速度を気にする必要はありません。リリース用コンパイルでは無視されるので、最終的な実行速度効率には影響を与えないためです。

同様の理由で、デバッグコードによる実行ファイルサイズの増加も心配する必要はありません。

(「プログラミングのはなし」は1998年1月から1999年1月にかけて作成されたコンテンツです。)