在assert中添加自定义消息?


129

有没有一种方法可以添加或编辑assert引发的消息?我想使用类似

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

然后,编译器添加linetime等等。

可能吗?


您可以像这样定义一个宏。
HelloGoodbye 2015年

Answers:


240

我所见过的一个hack是使用&&运算符。由于指针“为真”(如果非空),因此可以执行以下操作而无需更改条件:

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

由于assert显示失败的情况,因此也会显示您的消息。如果还不够,您可以编写自己的myAssert函数或宏,以显示所需的内容。


27
另一种选择是反转操作数并使用逗号运算符。您需要额外的括号,以免逗号不能作为参数之间的分隔符:assert(("A must be equal to B", a == b));
Keith Thompson

3
不过,能够打印变量的值也很好,例如:assert(a == b && "A (" << A << ") is not equal to B (" << B << ")");
弗兰克(Frank)

7
@Frank printf如果打印了任何内容,则返回非零值,因此您可以执行类似的操作assert(a == b && printf("a (%i) is not equal to b (%i)", a, b)),尽管此时您可能应该编写自己的断言包装器。
zneak

1
错误的代码!我不明白!如果a == b为false,则and-expression也应为false,因此不应评估该字符串。
ragnarius

1
@TUIlover,这不是C字符串文字的工作方式;它们是编译时常量,并且在此上下文中的使用已被轻松优化。没有运行时成本。
zneak

45

另一种选择是反转操作数并使用逗号运算符。您需要额外的括号,因此逗号不会被视为参数之间的定界符:

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

(这是从上面的注释中复制的,以提高可见性)


3
这是一种很好的方法,只有一个小问题,当在g ++中使用`-Wunused-value
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:需要非空参数

预期:ptr!= nullptr

来源:C:\ MyProject \ src.cpp,第22行

干净整洁,随时在您的代码中使用它=)


好一个。非常有用
Killrazor

我有点困惑。#Expr是否被视为直接替换的字符串?#Expr和Expr有什么区别?
Minh Tran

@MinhTran假设您的断言条件为x == y。然后Expr将扩展为if( !(x == y)),这是检查条件的地方,并且#Expr将扩展为字符串文字"x == y",然后将其放入错误消息中。
尤金·玛格达利兹

不幸的是,由于使用保留标识符,此解决方案导致未定义的行为。
记得莫妮卡


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
“因为断言错误的读者将始终从错误消息中查找文件并进行换行,”-仅当他们勤奋工作时。
杰森S

只有当他们想要修复错误时,您的意思才是……多么愚蠢的评论
变态

1
不能。您越容易使人们看到问题,他们就越有可能采取行动。
杰森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
修改编译器的标头不是一个好主意。
罗斯岭
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.