C++ 添加消息断言

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3767869/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 13:39:24  来源:igfitidea点击:

Adding message to assert

c++loggingdebuggingassert

提问by tauran

Hallo!

你好!

I'm looking for a way to add custom messages to assert statements. I found this questions Add custom messages in assert?but the message is static there. I want to do something like this:

我正在寻找一种将自定义消息添加到断言语句的方法。我发现这个问题在断言中添加自定义消息?但消息在那里是静态的。我想做这样的事情:

assert((0 < x) && (x < 10), std::string("x was ") + myToString(x));

When the assertion fails I want the normal output plus for example "x was 100".

当断言失败时,我想要正常输出加上例如“x 是 100”。

回答by Konrad Rudolph

You are out of luck here. The best way is to define your own assertmacro.

你在这里倒霉了。最好的方法是定义自己的assert宏。

Basically, it can look like this:

基本上,它看起来像这样:

#ifndef NDEBUG
#   define ASSERT(condition, message) \
    do { \
        if (! (condition)) { \
            std::cerr << "Assertion `" #condition "` failed in " << __FILE__ \
                      << " line " << __LINE__ << ": " << message << std::endl; \
            std::terminate(); \
        } \
    } while (false)
#else
#   define ASSERT(condition, message) do { } while (false)
#endif

This will define the ASSERTmacro only if the no-debug macro NDEBUGisn't defined.

这将定义ASSERT只有在没有调试宏宏NDEBUG没有定义。

Then you'd use it like this:

然后你会像这样使用它:

ASSERT((0 < x) && (x < 10), "x was " << x);

Which is a bit simpler than your usage since you don't need to stringify "x was "and xexplicitly, this is done implicitly by the macro.

这比您的用法简单一点,因为您不需要字符串化"x was "x显式,这是由宏隐式完成的。

回答by Cameron

There are some old tricks to include messages without writing your own routines:

有一些古老的技巧可以在不编写自己的例程的情况下包含消息:

The first is this:

第一个是这样的:

bool testbool = false;
assert(("this is the time", testbool));

There is also:

还有:

bool testbool = false;
assert(testbool && "This is a message");

The first one works, because the inside parens expression result is the value of 'testbool'. The second one works, because the value of the string is going to be non-zero.

第一个有效,因为里面的括号表达式结果是'testbool'的值。第二个有效,因为字符串的值将是非零的。

回答by Alsk

A better alternative is to teach the debugger to stop on assert when it fails, then you could examine not only the x value but any other information including call stack. Perhaps, this is what you are really looking for. Sample implementation is mentioned here Ways to show your co-programmers that some methods are not yet implemented in a class when programming in C++

更好的选择是教调试器在断言失败时停止断言,然后您不仅可以检查 x 值,还可以检查任何其他信息,包括调用堆栈。也许,这就是您真正要寻找的。此处提到了示例实现向您的合作程序员展示某些方法在使用 C++ 编程时尚未在类中实现的方法

回答by AlcubierreDrive

#define ASSERT_WITH_MESSAGE(condition, message) do { \
if (!(condition)) { printf((message)); } \
assert ((condition)); } while(false)

回答by Gregory Pakosz

For the sake of completeness, I published a drop-in 2 files assert macro implementation in C++:

为了完整起见,我在 C++ 中发布了一个插入的 2 个文件 assert 宏实现:

#include <pempek_assert.h>

int main()
{
  float min = 0.0f;
  float max = 1.0f;
  float v = 2.0f;
  PEMPEK_ASSERT(v > min && v < max,
                "invalid value: %f, must be between %f and %f", v, min, max);

  return 0;
}

Will prompt you with:

将提示您:

Assertion 'v > min && v < max' failed (DEBUG)
  in file e.cpp, line 8
  function: int main()
  with message: invalid value: 2.000000, must be between 0.000000 and 1.000000

Press (I)gnore / Ignore (F)orever / Ignore (A)ll / (D)ebug / A(b)ort:

Where

在哪里

  • (I)gnore: ignore the current assertion
  • Ignore (F)orever: remember the file and line where the assertion fired and ignore it for the remaining execution of the program
  • Ignore (A)ll: ignore all remaining assertions (all files and lines)
  • (D)ebug: break into the debugger if attached, otherwise abort()(on Windows, the system will prompt the user to attach a debugger)
  • A(b)ort: call abort()immediately
  • (I)gnore:忽略当前断言
  • Ignore (F)orever:记住断言触发的文件和行,并在程序的剩余执行过程中忽略它
  • Ignore (A)ll:忽略所有剩余的断言(所有文件和行)
  • (D)ebug:如果附加了就闯入调试器,否则abort()(在Windows上,系统会提示用户附加调试器)
  • A(b)ort:abort()立即调用

You can find out more about it there:

你可以在那里找到更多关于它的信息:

Hope that helps.

希望有帮助。

回答by solstice333

Extending on Kondrad Rudolph's answer:

扩展康德拉鲁道夫的回答:

#include <iostream>

#ifdef NDEBUG
#define assert(condition, message) 0
#else
#define assert(condition, message)\
   (!(condition)) ?\
      (std::cerr << "Assertion failed: (" << #condition << "), "\
      << "function " << __FUNCTION__\
      << ", file " << __FILE__\
      << ", line " << __LINE__ << "."\
      << std::endl << message << std::endl, abort(), 0) : 1
#endif

void foo() {
   int sum = 0;
   assert((sum = 1 + 1) == 3, "got sum of " << sum << ", but expected 3");
}

int main () {
   foo();
}

Output is...

输出是...

Assertion failed: ((sum = 1 + 1) == 3), function foo, file foo.cpp, line 13.
got sum of 2, but expected 3
zsh: abort      ./a.out

which is similar to what the std::assert macro outputs on my system just with the additional user defined message

这类似于 std::assert 宏在我的系统上输出的内容,只是附加了用户定义的消息

回答by Feng Wang

Yes, this is possible.

是的,这是可能的。

To enable expression like better_assert((0 < x) && (x < 10), std::string("x was ") + myToString(x));, we are supposed to have a corresponding macro in a form of

要启用类似的表达式better_assert((0 < x) && (x < 10), std::string("x was ") + myToString(x));,我们应该有一个相应的宏,其形式为

#define better_assert(EXPRESSION, ... ) ((EXPRESSION) ? \
(void)0 : print_assertion(std::cerr, \
"Assertion failure: ", #EXPRESSION, " in File: ", __FILE__, \ 
" in Line: ", __LINE__ __VA_OPT__(,) __VA_ARGS__))

in which print_assertionis a proxy function to do the assertion. When the EXPRESSIONis evaluated false, all the debug information, the __VA_ARGS__, will be dumped to std::cerr. This function takes arbitrary numbers of arguments, thus we should implement a variadic templated function:

其中print_assertion是执行断言的代理函数。当EXPRESSION评估false,所有调试信息的__VA_ARGS__,将被转储到std::cerr。这个函数接受任意数量的参数,因此我们应该实现一个可变参数模板函数:

template< typename... Args >
void print_assertion(std::ostream& out, Args&&... args)
{
    out.precision( 20 );
    if constexpr( debug_mode )
    {
        (out << ... << args) << std::endl;
        abort();
    }
}

In the previous implementation, the expression (out << ... << args) << std::endl;make use of fold expression in C++17 (https://en.cppreference.com/w/cpp/language/fold); the constant expression debug_modeis related to the compilation options passed, which is can be defined as

在前面的实现中,表达式(out << ... << args) << std::endl;使用了 C++17 中的折叠表达式(https://en.cppreference.com/w/cpp/language/fold);常量表达式debug_mode与传递的编译选项有关,可以定义为

#ifdef NDEBUG
    constexpr std::uint_least64_t debug_mode = 0;
#else
    constexpr std::uint_least64_t debug_mode = 1;
#endif

It also worth mentioning that the expression if constexpr( debug_mode )makes use of constexpr if (https://en.cppreference.com/w/cpp/language/if) imported since C++17.

还值得一提的是,该表达式if constexpr( debug_mode )使用了自 C++17 以来导入的 constexpr if ( https://en.cppreference.com/w/cpp/language/if)。

To wrap everything up, we have:

总结一下,我们有:

#ifdef NDEBUG
    constexpr std::uint_least64_t debug_mode = 0;
#else
    constexpr std::uint_least64_t debug_mode = 1;
#endif

template< typename... Args >
void print_assertion(std::ostream& out, Args&&... args)
{
    out.precision( 20 );
    if constexpr( debug_mode )
    {
        (out << ... << args) << std::endl;
        abort();
    }
}
#ifdef better_assert
#undef better_assert
#endif
#define better_assert(EXPRESSION, ... ) ((EXPRESSION) ? (void)0 : print_assertion(std::cerr, "Assertion failure: ",  #EXPRESSION, " in File: ", __FILE__, " in Line: ",  __LINE__ __VA_OPT__(,) __VA_ARGS__))

A typical test case demonstrating its usage can be:

展示其用法的典型测试用例可以是:

double const a = 3.14159265358979;
double const b = 2.0 * std::asin( 1.0 );
better_assert( a==b, " a is supposed to be equal to b, but now a = ", a, " and b = ", b );

This will produce something error message like:

这将产生一些错误信息,如:

Assertion failure: a==b in File: test.cc in Line: 9 a is supposed to be equal to b, but now a = 3.1415926535897900074 and b = 3.141592653589793116
[1]    8414 abort (core dumped)  ./test

And the full source code is available in this repo: https://github.com/fengwang/better_assert

完整源代码可在此 repo 中找到:https: //github.com/fengwang/better_assert

回答by Austin_Anderson

going along with Konrad Rudolf's answer you can do it a bit more concise with

与康拉德鲁道夫的回答一起,你可以更简洁地使用

#include <assert.h>
#include <stdio.h>
#define ASSERT(condition,...) assert( \
    condition|| \
    (fprintf(stderr,__VA_ARGS__)&&fprintf(stderr," at %s:%d\n",__FILE__,__LINE__)) \
);

which also works in C,

这也适用于C,

it works using the general idea from some of the answers to the question you linked, but the macro allows it to be a little more flexible

它使用您链接的问题的一些答案中的一般思想来工作,但是宏使它变得更加灵活