アサートにカスタムメッセージを追加しますか?


129

アサートによってスローされたメッセージを追加または編集する方法はありますか?次のようなものを使用したい

assert(a == b, "A must be equal to B");

次に、コンパイラは時間などを追加します...

出来ますか?


このように、マクロを定義できます。
HelloGoodbye 2015

回答:


240

私が見たハックは、&&演算子を使用することです。ポインターがnullでない場合、ポインターは「真」であるため、条件を変更せずに以下を実行できます。

assert(a == b && "A is not equal to B");

assertは失敗した状態を示しているため、メッセージも表示されます。それだけでは不十分な場合は、必要なmyAssertものを表示する独自の関数またはマクロを作成できます。


27
もう1つのオプションは、オペランドを逆にしてコンマ演算子を使用することです。コンマは引数の間の区切り文字として扱われませんので、あなたは余分な括弧を必要とする:assert(("A must be equal to B", a == b));
キース・トンプソン

3
以下のように、変数の値を印刷できるように、けれどもそれは、いいだろう:assert(a == b && "A (" << A << ") is not equal to B (" << B << ")");
フランク・

7
@Frankは、printf何かを出力した場合にゼロ以外の値を返すため、などの操作を実行できますassert(a == b && printf("a (%i) is not equal to b (%i)", a, b))が、その時点でおそらく独自のアサートラッパーを作成する必要があります。
zneak 2013

1
悪いコード!分かりません!a == bがfalseの場合、and-expressionもfalseである必要があるため、文字列は評価されません。
ragnarius 14年

1
@TUIlover、それはC文字列リテラルが機能する方法ではありません。それらはコンパイル時の定数であり、このコンテキストでの使用は簡単に最適化されます。ランタイムコストはありません。
zneak

45

もう1つのオプションは、オペランドを逆にしてコンマ演算子を使用することです。コンマが引数間の区切り文字として扱われないように、追加の括弧が必要です。

assert(("A must be equal to B", a == b));

(これは、見やすくするために、上記のコメントからコピーされました)


3
これは素晴らしいアプローチで、1つの小さな問題で、それは「警告:カンマ演算子の左オペランドは効果がありません」と表示されます`-Wunused-値と++グラムでコンパイルするとき
v010dya

1
またはマクロを使用:#ifndef m_assert #define m_assert(expr、msg)assert((msg、expr))#endif
Szymon Marczak

マクロラッパーを使用すると、GCCの警告を回避することができます:#define m_assert(expr, msg) assert(( (void)(msg), (expr) ))
Jander

25

メッセージを受け取り、すべてを明確に出力するassertマクロの私のバージョンは次のとおりです。

#include <iostream>

#ifndef NDEBUG
#   define M_Assert(Expr, Msg) \
    __M_Assert(#Expr, Expr, __FILE__, __LINE__, Msg)
#else
#   define M_Assert(Expr, Msg) ;
#endif

void __M_Assert(const char* expr_str, bool expr, const char* file, int line, const char* msg)
{
    if (!expr)
    {
        std::cerr << "Assert failed:\t" << msg << "\n"
            << "Expected:\t" << expr_str << "\n"
            << "Source:\t\t" << file << ", line " << line << "\n";
        abort();
    }
}

今、これを使うことができます

M_Assert(ptr != nullptr, "MyFunction: requires non-null argument");

失敗した場合は、次のようなメッセージが表示されます。

アサートに失敗しました:MyFunction:null以外の引数が必要です

予想:ptr!= nullptr

ソース:C:\ MyProject \ src.cpp、22行目

素晴らしく、きれいです。コードで自由に使用してください=)


良いですね。非常に便利
Killrazor

私は少し混乱しています。#Exprは直接置換の文字列として扱われますか?#ExprとExprの違いは何ですか?
Minh Tran

@MinhTranアサート条件がであると仮定しましょうx == y。次に、Exprが展開されif( !(x == y))、ここで条件がチェック"x == y"されます。#Exprが文字列リテラルに展開され、エラーメッセージに表示されます。
Eugene Magdalits 2016年

残念ながら、このソリューションでは予約済み識別子を使用しているため、未定義の動作が発生します。
モニカ

19
BOOST_ASSERT_MSG(expre, msg)

http://www.boost.org/doc/libs/1_51_0/libs/utility/assert.html

これを直接使用するか、Boostのコードをコピーします。また、Boostアサートはヘッダーのみであるため、Boostのすべてをインストールしたくない場合は、その単一のファイルを取得することもできます。


@ Jichao、assertインターフェイスを実装するとはどういう意味ですか?
Tarc

7

zneakの答えはコードを多少複雑にしているので、より良いアプローチは、あなたが話している文字列のテキストを単にコメントすることです。つまり:

assert(a == b); // A must be equal to B

アサートエラーのリーダーは、エラーメッセージからファイルと行を検索するため、ここで完全な説明が表示されます。

結局のところ、これは:

assert(number_of_frames != 0); // Has frames to update

これよりもよく読む:

assert(number_of_frames != 0 && "Has frames to update");

コードの人間による解析の観点から。読みやすさ。言語ハックでもありません。


1
「アサートエラーのリーダーは、エラーメッセージからファイルと行を検索するため」-勤勉である場合のみ。
Jason S

彼らがバグを修正したい場合にのみ...なんてばかげたコメント
変態

1
いいえ。問題を見つけやすくするほど、アクションを起こす可能性が高くなります。
Jason S

肩をすくめる反対。
変態

2

assertはマクロと関数の組み合わせです。あなたが使用して、独自のマクロ/関数を定義することができ__FILE____BASE_FILE____LINE__カスタムメッセージを受け取り、独自の機能で、等


-6

vcの場合、assert.hに次のコードを追加します。

#define assert2(_Expression, _Msg) (void)( (!!(_Expression)) || (_wassert(_CRT_WIDE(#_Msg), _CRT_WIDE(__FILE__), __LINE__), 0) )

11
コンパイラのヘッダーを変更することは悪い考えです。
ロスリッジ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.