20

Often one wants to print out additional information if an assert fails. A way to do that is this:

assert(vec.size() > i || 
  !(std::cerr << "False: " << vec.size() << ">" << i))

This way the actual sizes are printed when the assert fails. But it's ugly, and also it's easy to forget the ! , which will make the assertion condition true and the program will just continue.

What do people use instead to print additional information on assertion failure, like above?

Frank
  • 64,140
  • 93
  • 237
  • 324
  • 1
    This doesn't answer your question, but consider using if-blocks, rather than assertions, to catch errors. You may want to use assert(false) after handling the error, but I find that the if-block approach is much more flexible and readable than assertions. Tired programmers sometimes mistake what happens when the assertion evaluates to true or false. – Collin Dauphinee Feb 03 '10 at 16:59
  • possible duplicate of [Add custom messages in assert?](http://stackoverflow.com/questions/3692954/add-custom-messages-in-assert) – Patrizio Bertoni Apr 20 '15 at 17:17

10 Answers10

15
#define ASSERT(condition) { if(!(condition)){ std::cerr << "ASSERT FAILED: " << #condition << " @ " << __FILE__ << " (" << __LINE__ << ")" << std::endl; } }

Usage:

ASSERT(vec.size()>1);

Result:

ASSERT FAILED: vec.size()>1 @ main.cpp (17)

You can optionally put DebugBreak() or exit(-1) or watever into the macro, depending on your needs.

Updated macro with separated left and right side:

#define ASSERT(left,operator,right) { if(!((left) operator (right))){ std::cerr << "ASSERT FAILED: " << #left << #operator << #right << " @ " << __FILE__ << " (" << __LINE__ << "). " << #left << "=" << (left) << "; " << #right << "=" << (right) << std::endl; } }

Usage:

ASSERT(a,>,b);

Result:

ASSERT FAILED: a>b @ assert2.cpp (8). a=3; b=4
Notinlist
  • 16,144
  • 10
  • 57
  • 99
  • But it will print the actual size of the vector, not "vec.size()", right? – Frank Feb 03 '10 at 16:46
  • At least for g++ this code still gets included for -DNDEBUG (assert isn't). – Benjamin Bannier Feb 03 '10 at 16:47
  • @dehmann: It will print `vec.size()` not 235. You do not need more because you can call DebugBreak() or whatever so you will have a debugger at the right place and you can watch it. @Benjamin: You can define the `ASSERT()` macro as empty depending on an other macro's existence. – Notinlist Feb 03 '10 at 16:50
  • 1
    Right idea -- put the extra info into the definition of assert. (Typical implementations already do this.) But there are subtleties in getting the definition just right, and this one doesn't have all the details quite right. Game Programming Gems Vol I has some good articles on building a quality assert macro. – Adrian McCarthy Feb 03 '10 at 17:01
  • Hmm, I'd like it better if it actually printed `235` or whatever the size is, like the code I gave in the question. That might save me time since I might not actually have to start the debugger (the program might run for a long time before it actually reaches that point). – Frank Feb 03 '10 at 17:11
  • 1
    In this case you have to handle the left side, the right side and the operator separated. You can construct a similar macro like that. #define ASSERT(left,operator,right) { if(!(left operator right)){ ... << #left << "=" << (left) << "; " << #right << "=" << (right) << ... } } – Notinlist Feb 03 '10 at 17:18
5

What do people use instead to print additional information on assertion failure, like above?

Generally I'd just add a string literal describing the meaning of the condition:

assert(v.size() > i && "The vector really needs to be larger");

But perhaps a macro like this:

#include <cassert>
#include <vector>
#include <iostream>

//#define NDEBUG

#ifndef NDEBUG
#define ASSERT_EX(condition, statement) \
    do { \
        if (!(condition)) { statement; assert(condition); } \
    } while (false)
#else
#define ASSERT_EX(condition, statement) ((void)0)
#endif

int main()
{
    std::vector<int> v;
    unsigned i = 1;
    ASSERT_EX(v.size() > i, std::cerr << "i = " << i << ", v.size() = " << v.size() << '\n');
}

Here it would be nice, though, if statement wouldn't have side-effects, changing how condition evaluates. :)

UncleBens
  • 40,819
  • 6
  • 57
  • 90
3

assert() compiles to nothing in Release build of many compilers. It is not something that has any value for production code.

I use a construct like this:

#include <cstdlib>
#include <vector>
#include <algorithm>
#include <ctime>
#include <iostream>
using namespace std;


template<typename T> inline bool Verify(T const& t,char const* Expression, char const* File, unsigned long Line)
{
    bool b = !(!t);
    if( b )
        return true;
    // verify failed -- report it 
    std::cerr <<  "Assertion '" << Expression << "' Failed @ " << File << ":" << Line << endl;
    return false;
};

#define verify(exp) (bool)( Verify(exp, #exp, __FILE__, __LINE__) )


template<typename Iter> void doit(Iter const begin, const Iter & end)
{
    for( ; begin != end; ++begin )
        ;
}

int main()
{
    int n = 1;
    n *= 2;
    verify( n == 3 );
    return 0;
}

Program Output:

Assertion 'n == 3' Failed @ .\main.cpp:32
John Dibling
  • 99,718
  • 31
  • 186
  • 324
1

Most extended assertion handlers are of the form:

assert_x(CONDITION,EXPLANATION);

what you want is something along the lines of

assert_args(condition, explanation, ...);

So:

extern string build_assert_string(const string&, explanation, ...);

#define ASSERT_ARGS(CONDITION,build_assert_string EXPLANATION)

call as:

ASSERT_ARGS(x > 0, ("x should be > 0 but it is %d", x));

The function build_assert_string is trivial.

lilburne
  • 565
  • 1
  • 3
  • 10
1

I think the following makes sense. Instead of this:

assert(vec.size() > i || 
  !(std::cerr << "False: " << vec.size() << ">" << i))

just do this:

assert(vec.size() > i || 
  assert_msg(vec.size() << ">" << i));

where assert_msg is defined as something like this:

#define assert_msg(x) !(std::cerr << "Assertion failed: " << x << std::endl)
Frank
  • 64,140
  • 93
  • 237
  • 324
0

I use something like this:

#define ASSERT(lhs, op, rhs) assert_template((lhs##op##rhs), "(" #lhs #op #rhs ")", lhs, rhs, __FILE__, __LINE__)

template <typename t1, typename t2>
void assert_template(const bool result, const char expr[], t1 lhs, t2 rhs, const char file_name[], const long line_number)
{
    if (!result)
    {
        std::cerr << "Assertion failed";
        std::cerr << "    " << expr;
        std::cerr << "    lhs = " << lhs;
        std::cerr << "    rhs = " << rhs;
        std::cerr << "    File: \"" << file_name << "\"";
        std::cerr << "    Line: " << std::dec << line_number;

        throw "Assertion failed";
    }
};

The use syntax is a little weird as in ASSERT(vec.size(), >, 1) or ASSERT(error, ==, 0). The upside is that it also prints out the values of the left and right hand side. On Windows I also like to throw in GetLastError() and WSAGetLastError().

kipkennedy
  • 372
  • 1
  • 6
0

Here's what I use, breaks on the actual line that failed, rather than elsewhere in the stack. Works on MSVC and GCC, and uses a little boost magic and generates an assertion dialog:

#include <boost/current_function.hpp>

#if defined(NDEBUG)
# define MY_ASSERT(expr) ((void)0)
#else
    int assertion_failed(char const *expr, char const *function, char const *file, long line);
# if defined(_WIN32)
#  define debugbreak __debugbreak
# else
#  define debugbreak __builtin_trap
# endif
# define MY_ASSERT(expr) ((expr) || !assertion_failed(#expr, BOOST_CURRENT_FUNCTION, __FILE__, __LINE__) || (debugbreak(), 0))
#endif

#if !defined(NDEBUG)
int assertion_failed(char const *expr, char const *function, char const *file, long line)
{
#if defined(_WIN32)
    return ::_CrtDbgReport(_CRT_ASSERT, file, line, NULL, "%s", expr);
# else
    return !0;
# endif
}
#endif
Matt Joiner
  • 112,946
  • 110
  • 377
  • 526
0

I use either an if statement or wxASSERT_MSG from wxWidgets.

If you use a framework, see if it provides some useful assertion tools.

Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154
0

I made this for plain C, based on Notinlist answer (thank you!):

my_assert.c:

void _assert_int(char *astr, char *oper, char *bstr, int a, int b, char *file, int line) {
  printf("\nAssertion failed: %s %s %s\n%s = %d\n%s = %d\nfile: %s\nline: %d\n", astr, oper, bstr, astr, a, bstr, b, file, line);
  exit(1);
}

void _assert_str_equal(char *vara, char *varb, char *a, char *b, char *file, int line) {

  if (a == b) {
#ifdef TREAT_BOTH_NULL_STRS_AS_ERROR
    if (a != 0) return;
    goto loc_failed;
#else
    return;
#endif
  }

  if ((a == 0) || (b == 0) || (strcmp(a, b) != 0))  {
loc_failed:
    printf("\nAssertion failed: %s == %s\n%s = %s\n%s = %s\nfile: %s\nline: %d\n", vara, varb, vara, a, varb, b, file, line);
    exit(1);
  }

}

my_assert.h:

#define TREAT_BOTH_NULL_STRS_AS_ERROR

#define assert_int(left,operator,right) do { if(!((left) operator (right))) _assert_int(#left, #operator, #right, left, right, __FILE__, __LINE__); } while (0)

#define assert_str_equal(left,right) do { _assert_str_equal(#left, #right, left, right, __FILE__, __LINE__); } while (0)

usage:

assert_int(a,==,b);

assert_str_equal(str1,str2);

check also the seatest unit test framework

Bernardo Ramos
  • 4,048
  • 30
  • 28
0

How about using "fprintf" to replace the std::cerr? "fprintf" returns number of characters printed (>= 0 when succeeds) and you may use it like this (very easy to remember and clear to read ... at least for me):

assert(vec.size() > i || (fprintf(stderr, "False: %d > %d\n", vec.size(), i) >= 0);

You can then make it a inline function (in C) for convenience, name it like "assert_vecSize_largerThan(...)".