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

ABORT する

前のトピックではデバッグコードの話をしましたが、実際にバグが検出されたときには何をすれば良いでしょうか?既に述べた通り、大袈裟にバグをアナウンスしなければなりません(もちろん今はデバッグ時の話をしているのです)。

ひとつの方法は、メッセージを表示してから ABORT することです。前のトピックのコードでは、例えば次のようにします。

SAMPLE
CODE
void Greet( GreetingTime Time )
{
    #ifdef DEBUG
        if ( ( Time != MORNING ) && ( Time != EVENING ) ) {
            // バグ検出!
            cout << "BUG Detected at " << __FILE__
                 << "(" << __LINE__ << ")" << endl;
            ABORT();
        }
    #endif

   (以下省略)
}

これで、上の関数 Greet の不正な呼び出しが検出されたときには、メッセージが表示されプログラムは異常停止します。__FILE__ と __LINE__ はソースコード中のどのデバッグコードにひっかかったのかを知るために必要です。また、ABORT は

#define ABORT() abort()

のように定義したマクロを用います。これは、そのときの状況によって abort() の動作を変えたい場合があるためです。お気付きの方もいるでしょうが、C++ を使っている場合は ABORT のかわりに terminate() を利用した方がスマートです(terminat() のデフォルトの動作は abort()を呼び出すことです)。

上の例では話を単純にするためそのまま使っていますが、ABORT と同様の理由で cout も別の関数か何かでラッピングすると流用性が増します。たとえば UNIX 用に書いたコードを Windows に流用し、バグ検出時のメッセージは MessageBox を使って表示したいという場合がこれにあたります。

ABORT の使い所をもうひとつ紹介します。それは、「絶対に到達しない場所に書く」ということです。また同じ関数で説明します。

SAMPLE
CODE
void Greet( GreetingTime Time )
{
    switch ( Time ) {

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

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

    default:
        // ここに到達したらバグ!
        cout << "BUG Detected at " << __FILE__
             << "(" << __LINE__ << ")" << endl;
        ABORT();
    }
}

上のプログラムでは、関数 Greet は2つのパラメータ MORNING/EVENING しか認めていないので、default の部分には絶対に到達しないはずです。もしここに到達したら関数の呼び出し側のバグです。そこで default に ABORT() と書くことによって、このバグを積極的に検出しようとしているわけです。

さて、これで ABORT の使い方を2つと、デバッグコードの書き方を説明しました。これらをもっとずっとスマートに書く方法があります。それが ASSERT です。

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