読者です 読者をやめる 読者になる 読者になる

稲枝の押入れ

いなえが適当なことを書いては、しまっておく場所

DXライブラリでasserionマクロを使えるようにする

C言語にはassertという関数がある。

詳細は(ここらへん)http://www.c-tipsref.com/reference/assert/assert.htmlを見たりググったりして欲しい。

これは簡単に言ってしまえばプログラマの意図を記述するのに使われる。

例えば、除算を定義する際にゼロ除算を除きたい場合は、assert(割る数!=0)と書いておくと、間違って0で割ってしまった時にそこでプログラムを強制終了して、「割る数!=0が満たされてないよ?」的なメッセージを出してくれる。

さて、これをDXライブラリでも使えるようにしたい。assert関数を使えば良いんじゃないの?と思うかもしれないが、assert関数はプログラムをその場で強制終了する。つまりはDxLib_End関数が最後に呼ばれず、場合によっては変にプロセスが残ったままになってしまう。

解決策として、適当なプログラム全体の管理クラス的なものを作って、そいつのデストラクタにDxLib_End関数を書けば良いのではないか、と思うかもしれないがそうも行かないらしい。assert関数が呼ばれた場合はデストラクタも呼ばれないらしいのだ。

さて、ということで自作assertだ。単にラップすれば良いんじゃないの(=Adopterパターンでなんとかなるんじゃないの)と思うかもしれないが、せっかくなので多少使いやすいものを作りたいと思ってしまった。

そして出来たのが以下である。

assertDx.h

//
//assert
//

//assertionマクロ。こっちをつかう。
//意図していない部分や、ファイル名、何行目か等の情報が得られる。
#define assertDx(assertion) AssertDx(assertion,#assertion,__FILE__,__LINE__,__FUNCTION__)

//assertionマクロ。こっちをつかう。
//意図していない部分や、ファイル名、何行目か等の情報が得られる。
//デバッグ用に情報(std::string)を1つ埋め込める
#define assertDxInfo(assertion,info) AssertDx(assertion,#assertion,__FILE__,__LINE__,__FUNCTION__,info)


//マクロが実際に動く時の中身の関数。こちらではなくassertDxを使う
void AssertDx(bool assert_bool, std::string assert_tex, std::string file, int line, std::string func);

//マクロが実際に動く時の中身の関数。こちらではなくassertDxを使う
//デバッグ用に情報を1つ埋め込める
void AssertDx(bool assert_bool, std::string assert_tex, std::string file, int line, std::string func, std::string info);

assertDx.cpp


//マクロが実際に動く時の中身の関数。こちらではなくassertDxを使う
void AssertDx(bool assert_bool, std::string assert_tex, std::string file, int line, std::string func) {
    if (assert_bool == false) {
        //意図しない動作をしている旨を表示
        MessageBox(NULL, (
            "Assertion failed: \"" + assert_tex +
            "\",\n File:" + file
            + ",\n Line:" + std::to_string(line)
            + ",\n In Function:" + func
            ).c_str()
            , "Assertion failed", MB_OK | MB_ICONSTOP);

        DxLib_End();// DXライブラリ使用の終了処理
        exit(-1);//-1を渡して終了する。
    }
}


//マクロが実際に動く時の中身の関数。こちらではなくassertDxを使う
void AssertDx(bool assert_bool, std::string assert_tex, std::string file, int line, std::string func, std::string info) {
    if (assert_bool == false) {
        //意図しない動作をしている旨を表示
        MessageBox(NULL, (
            "Assertion failed: \"" + assert_tex +
            "\",\n File:" + file
            + ",\n Line:" + std::to_string(line)
            + ",\n In Function:" + func
            + ",\n Infomation:" + info
            ).c_str()
            , "Assertion failed", MB_OK | MB_ICONSTOP);

        DxLib_End();// DXライブラリ使用の終了処理
        exit(-1);//-1を渡して終了する。
    }
}

正直申し上げてよく分からず書いているところがある(特にWinAPI周り)ので動作については保証できないが、一応こんな感じで良い感じに動く。

使い方としては

//読み込みに失敗していない
    assertDxInfo(load_result != -1, handle_name);

として読み込みが失敗しているのにプログラムがそのまま動くのを阻止したりと言った風に使う。(ちなみにこのassertDxInfo関数は、assertion警告が出る時に追加表示する情報を付加できる)

改善点はまだまだありそうだが、今のところ実用に耐えているっぽいので(そもそもそんなに引っかからないので本当に耐えているのかは不明)これでいいかな、という感じだ。

そしてここに晒すことによってマズイ所を指摘してもらえて改善できるのではないかと淡い期待をしているので、何か気付いたことがあったら教えていただけると嬉しい。