代码之家  ›  专栏  ›  技术社区  ›  tauran

添加要断言的消息

  •  37
  • tauran  · 技术社区  · 15 年前

    我发现这个问题 Add custom messages in assert? 但信息是静态的。我想这样做:

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

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

    7 回复  |  直到 9 年前
        1
  •  78
  •   Konrad Rudolph    10 年前

    你在这儿运气不好。最好的方法是定义你自己的 assert

    #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
    

    这将定义 ASSERT 仅当没有调试宏 NDEBUG 未定义。

    然后你可以这样使用它:

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

    这比你的用法简单一点,因为你不需要字符串化 "x was " x

        2
  •  28
  •   Cameron    9 年前

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

    首先是:

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

    还有:

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

    第二个有效,因为字符串的值将是非零的。

        3
  •  10
  •   Community Mohan Dere    9 年前

    一个更好的替代方法是教导调试器在assert失败时停止,然后您不仅可以检查x值,还可以检查包括调用堆栈在内的任何其他信息。也许,这才是你真正想要的。 这里提到了示例实现 Ways to show your co-programmers that some methods are not yet implemented in a class when programming in C++

        4
  •  7
  •   AlcubierreDrive    15 年前
    #define ASSERT_WITH_MESSAGE(condition, message) do { \
    if (!(condition)) { printf((message)); } \
    assert ((condition)); } while(false)
    
        5
  •  3
  •   Gregory Pakosz    12 年前

    #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;
    }
    

    将提示您:

    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:
    

    在哪里?

    • (一) 忽略当前断言
    • 在程序的剩余执行中忽略它
    • Ignore(A)ll:忽略所有剩余断言(所有文件和行)
    • (D) ebug:如果附加了调试器,则进入调试器,否则 abort() (在窗户上, 系统将提示用户附加调试器)
    • 中止() 立即

    您可以在那里了解更多信息:

        6
  •  2
  •   solstice333    7 年前

    延续康德拉德·鲁道夫的回答:

    #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();
    }
    

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

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

        7
  •  1
  •   Feng Wang    7 年前

    是的,这是可能的。

    启用表达式 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__))
    

    在哪儿 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();
        }
    }
    

    (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
    

    值得一提的是 if constexpr( debug_mode ) 使用constexpr if( https://en.cppreference.com/w/cpp/language/if )自C++ 17导入。

    总而言之,我们有:

    #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__))
    

    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 );
    

    这将产生如下错误消息:

    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
    

    完整的源代码可在本报告中获得: https://github.com/fengwang/better_assert

        8
  •  -1
  •   Austin_Anderson    8 年前

    按照康拉德·鲁道夫的回答,你可以做得更简洁一点

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

    它在C语言中也起作用,