Adding message to assert - c++
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".
You are out of luck here. The best way is to define your own assert macro.
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 ASSERT macro only if the no-debug macro NDEBUG isn’t defined.
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 x explicitly, this is done implicitly by the macro.
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.
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++
#define ASSERT_WITH_MESSAGE(condition, message) do { \
if (!(condition)) { printf((message)); } \
assert ((condition)); } while(false)
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
For the sake of completeness, I published a drop-in 2 files assert macro implementation in C++:
#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
You can find out more about it there:
blog post
GitHub project
Hope that helps.
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
#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_assertion is a proxy function to do the assertion. When the EXPRESSION is 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:
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_mode is related to the compilation options passed, which is can be defined as
#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.
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
To take on Feng Wang answer, in newer versions of C++, anything inline is going to be optimized out. So you can have an inline function in a header file which does all the work.
inline constexpr void NOT_USED()
{
}
template <class T, class ...ARGS>
inline constexpr void NOT_USED(T && first, ARGS && ...args)
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-result"
static_cast<void>(first);
#pragma GCC diagnostic pop
NOT_USED(args...);
}
template<typename ... ARGS>
void SAFE_ASSERT(bool test_result, ARGS &&... args)
{
#ifdef _DEBUG
if(test_result)
{
(std::cerr << ... << args) << std::endl;
abort();
}
#else
NOT_USED(test_result, args...);
#endif
}
Some comments:
If _DEBUG is not defined, the function becomes empty so it can be optimized out 100%
If you call the function with a side effect, the non-debug code still works:
my_assert(c++ < --z, "the #define versions do not behave similarly");
These side effects are clearly visible here. However, if you call a function, it could be really difficult to know whether something happens in the function which was not otherwise expected.
There are ways to prevent such side effects from happening, though (Example). But all in all, in some cases, you need to call a function for the test and it may have a side effect and therefore needs to not be optimized out in non-debug code.
I use abort() because I know that stops the debugger properly, std::terminate() is the C++ way which in modern systems does the same thing, but if std::terminate() doesn't work for your debugger the abort() will.
The NOT_USED() is to avoid warnings about unused function parameters (if you don't have that warning, you may end up with expected bugs).
I have an implementation in snapdev: see safe_assert.h and not_used.h.
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,
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
Related
error: expected expression in variadic macros
I want to write a macros to print pairs of {variable name, variable value}. The variables are supposed to be arguments of variadic macros. I made a simple code, that produces compilation error: "expected expression" in cases when number of variables to print is less than maximum possible number. #define IS_EMPTY(...) ( sizeof( (char[]){#__VA_ARGS__} ) == 1 ) #define PRINT_VAR(x) std::cout << "\"" << #x << "\": " << (x) << " "; #define PRINT_VARS3(x, ...) {PRINT_VAR(x); } #define PRINT_VARS2(x, ...) {PRINT_VAR(x); \ if constexpr (not IS_EMPTY(__VA_ARGS__)) PRINT_VARS3(__VA_ARGS__); } #define PRINT_VARS1(x, ...) {PRINT_VAR(x); \ if constexpr (not IS_EMPTY(__VA_ARGS__)) PRINT_VARS2(__VA_ARGS__); } #define PRINT_VARS(x, ...) {PRINT_VAR(x); \ if constexpr (not IS_EMPTY(__VA_ARGS__)) {\ PRINT_VARS1(__VA_ARGS__); \ } \ std::cout << "\n";} int i = 100; float j = 200.5; int k = 300; float l = -0.576f; PRINT_VARS(i, j, k, l); // works fine //PRINT_VARS(i, j); // compilation error Thing that I cant understand, if I remove << (x) from second line, PRINT_VARS work with different number of arguments. What is the reason and how to fix it? Thank you! Removing << (x) from the second line makes code compliable and working except it cant printout the variables values. I expect the compiler not to check if constexpr branches at 0 condition. But it looks like empty VA_ARGS passed to PRINT_VAR macros that leads to this error. I have tried this code with gcc12 and clang14 compilers.
How to make online compilers to ignore debug statements in C++?
I am using these lines of code for debugging my C++ program. void dbg_out(){cerr << endl;} template<typename Head, typename... Tail> void dbg_out(Head H, Tail... T) { cerr << ' ' << H; dbg_out(T...); } #define dbg(...) cerr << "(" << #__VA_ARGS__ << "):", dbg_out(__VA_ARGS__) But the problem with this is that when I am using dbg function and submit on an online judge like codeforces or codechef it is increasing execution of code. Is there a way to make the online compiler to ignore the debug statements ?
You can make the preprocessor conditionally define the macro: #ifdef DEBUG_LOG #define dbg(...) std::cerr << "(" << #__VA_ARGS__ << "):", dbg_out(__VA_ARGS__) #else #define dbg(...) #endif Now if you compile with the option -DDEBUG_LOG, the log would be sent to std::cerr. An online judge wouldn't add that command line option, but you can locally.
Accessing variable values within a macro
Some time ago, I made this beautiful assert macro for c and c++ programs #define ASSERT(truthy, message) \ if (!(truthy)) \ {\ cout << message << " on line " << __LINE__ << " in file " << __FILE__ << ". Check was " << #truthy << endl;\ } Scatter ASSERT calls throughout your code, and it will warn you whenever the truthy value is not truthy! Very handy during development to remind you of potential mistakes. ex ASSERT(filesFound > 0, "Couldn't find any files, check your path!"); When filesFound is 0, the macro will print out Couldn't find any files, check your path! on line 27 in file openFiles.c. Check was filesFound > 0 Now what I want it to print, to give me even more relevant information, is the value of any variables passed into the truthy parameter. Like this Couldn't find any files, check your path! on line 27 in file openFiles.c. Check was filesFound > 0, filesFound is 0 This seems lisp-like territory, I wonder, is there any black magic c preprocessing that I can use to evaluate variables and functions to their values, without evaluating the truthy statement? I assume to be disappointed.
An alternative solution which I've always used is to support varargs in the macro and then force the assert user to specify the relevant message / variables - it's a little bit of extra work each time, but on the plus side you can get exactly the formatting that you want and include information not available in the "truthy" bit, e.g: #define ASSERT(truthy, message, ...) \ if (!(truthy)) \ {\ MyAssertHandler(__LINE__, __FILE__, #truthy, message, ##__VA_ARGS__); } Then you're handler is just a fairly standard var-arg function that can use e.g. vsnprintf to generate the message and output it, e.g. off the top of my head: void MyAssertHandler(int line, const char* file, const char* expressionStr, const char* format, ...) { // Note: You probably want to use vsnprintf instead to first generate // the message and then add extra info (line, filename, etc.) to // the actual output va_list args; va_start(args, format); vprintf(format, args); va_end(args); // Log to bug database, DebugBreak() if a debugger is attached, etc. } usage: ASSERT(IsBlah(), "BlahBlah: x = %.2f, name = %s", GetX(), GetName());
I cannot imagine a way to do it... except by passing another parameter #define ASSERT_PARAM(truthy, message, param) \ if (!(truthy)) \ {\ cout << message << " on line " << __LINE__ << " in file " << __FILE__ << ". Check was " << #truthy << ", value was " << param << endl;\ } You would use it that way: ASSERT_PARAM(filesFound > 0, "Couldn't find any files, check your path!", filesFound); getting: Couldn't find any files, check your path! on line 27 in file openFiles.c. Check was filesFound > 0, value was 0
What you are trying to do sounds very complicated. I'm afraid in C++ it's not possible. Technically what you are evaluating is a bool expression so you can pass it to a parser whenever the assertion fails. The parser then will build the expression tree, get the leaves (elements of the expression) and return them. The returned values then should be printed out. To do that you will need support for reflection which is actually not supported in C++ AFAIK.
Maybe not the dream solution, but you can pass whole statements to a macro. #define ASSERT(trusty, action) if (!trusty) { action } ASSERT(trusty, cout << a << b;) ASSERT(trusty, printf("%d, %f\n", a, b);)
I think you can split up the truthy Expression like they do it in the first answer here and then you can probably print the individual values. But I'm not sure if it actually works. The printing could then be resulved using a variadic template function
Perhaps you could compromise and only allow 2 variables and 1 operator in the assertion expression? If so, you could make an ad hoc solution like this: #include <iostream> #include <string> #define STRINGIFY(x) #x #define BIN_ASSERT(obj1, op, obj2, msg) \ if(!(obj1 op obj2)) \ { \ std::cout << msg << " on line " << __LINE__ \ << " in file " << __FILE__ \ << "." << std::endl \ << "Check was " \ << STRINGIFY(obj1) STRINGIFY(op) STRINGIFY(obj2) \ << "." << std::endl \ << "Operator " << #obj1 << ": " << obj1 \ << "." << std::endl \ << "Operator " << #obj2 << ": " << obj2 \ << "." << std::endl; \ } int main (void) { int x = 2; int y = 3; std::string s1 = "hello"; std::string s2 = "world"; BIN_ASSERT(1, +, -1, "Value zero"); std::cout << std::endl; BIN_ASSERT(x, ==, y, "Numbers not equal"); std::cout << std::endl; BIN_ASSERT(s1, ==, s2, "Strings not equal"); std::cout << std::endl; } Output: Value zero on line 30 in file test.c. Check was 1+-1. Operator 1: 1. Operator -1: -1. Numbers not equal on line 31 in file test.c. Check was x==y. Operator x: 2. Operator y: 3. Strings not equal on line 32 in file test.c. Check was s1==s2. Operator s1: hello. Operator s2: world.
I wonder if having the macro take a message is really that useful. A failed assertion is a message to the developer that there is a bug in the code that caused an exceptional behaviour or put the program in an unacceptable state. The user has less to do with it (if they even have access to the source code). The code below defines an ASSERT macro that takes a boolean expression, evaluates it and prints an informational message. The message contains a value that you've asked to inspect upon failing the assertion. The macro, just like the standard assert() macro (in <cassert>) goes on to call abort() (from <cstdlib>) to cause an abnormal program termination. This is what you want, because the program entered a state in which it didn't know what more to do. I'm using std::printf() here for brevity. You do whatever you want. #include <cstdlib> #include <cstdio> #define ASSERT(value, inspect) \ if (!(value)) { \ std::printf("ASSERTION FAILED: '%s', %s is %d: %s#%s:%d\n", #value, \ #inspect, inspect, __func__, __FILE__, __LINE__); \ abort(); \ } int foo() { return 42; } int main() { // ... ASSERT(foo() - 40 == 1, foo()); //... } Program run: $ ./a.out ASSERTION FAILED: 'foo() - 40 == 1', foo() is 42: main#prog.cc:16 Abort It's not possible to do exactly what you ask for without adding more parameters to the macro. At some point you'll have to stop and realize that you're spending time on creating a text string that you do not want to see.
You need to build an expression 'grabber' / builder. The macro would become something like: #define ASSERT_PARAM(truthy, message, param) \ if (!(truthy)) \ {\ Grabber g; g << #truthy; // grab expression as string g % truthy; // grab expression and values cout << message << " on line " << __LINE__ << " in file " << __FILE__ << ". Check was " << #truthy << ", value was " << param << endl;\ cout << g; \ } What does Grabber do? It is a bunch of crazy C++ that builds up an expression. It would overload every operator to 'grab' the params of the operator. Every operator returns a reference to the grabber, so it can grab the next operator. ie Grabber g; g % filesFound > 0; Since % (and * and /) have high precedence, the above parses like: ((g % filesFound) > 0) If template<typename T> Grabber::operator%(T const & val) just records (or prints) the value passed in (ie filesFound), and - importantly - returns itself (g) so that it becomes part of the next expression: ie it becomes g > 0. Causing template<typename T> Grabber::operator>(T const & val) to be called, and > 0 to be recorded. Then cout << g can spew out everything grabbed. As mentioned above "It is possible — the Catch library does it. But it’s hellishly difficult". P.S. you should wrap your macro in a do ... while 0 like this: #define ASSERT_PARAM(truthy, message, param) \ do \ { \ if (!(truthy)) \ {\ cout << message << " on line " << __LINE__ << " in file " << __FILE__ << ". Check was " << #truthy << ", value was " << param << endl;\ cout << g; \ } \ } while (0) What you have currently means that this is valid code: ASSERT(foo != 0) else { } And this is NOT valid code: if (foo != nullptr) ASSERT(foo->bar != nullptr); else x = 10;
Surprisingly, I solved a similar problem before, but I'm not sure if it could help you in this case. The original solution was proposed by Andrei Alexandrescu in the article Enhancing Assertions, and with no question, relying on some macro tricks. This amazing facility can be used as the following: string s1, s2; ... SMART_ASSERT(s1.empty() && s2.empty())(s1)(s2); And if something goes wrong, the message would be displayed Assertion failed in matrix.cpp: 879412: Expression: 's1.empty() && s2.empty()' Values: s1 = "Wake up, Neo" s2 = "It's time to reload." Be noted that, the SMART_ASSERT can capture infinite variables, theoretically. For implementation details, please check out the article.
C++ macro with variable arguments
1.#define debug(...) printf( __VA_ARGS__) 2.#define debug(...) std::cout<< __VA_ARGS__ Apparently, 1 is ok, 2 will get error when compiles. Is there any possibility to use "std::cout" with variable arguments? What's the point of this macro? 'debug' macro use to print something to debug the code. void test(const classtype1 &obj1,const classtype2 &obj2) { // rewrite operator<< debug(obj1,obj2); //if use printf, I must call tostring method(or something likes that) to //series the object to string. debug(obj1.tostring(),obj2.tostring()); ... }
You can do something like: #define DEBUG(x) do { std::osacquire( std::cerr ) << __FILE__ << ":" << __LINE__ << " " << x << std::endl; } while (0); And then wherever you want to use the macro: DEBUG( obj1.tostring() + " some stuff " + obj2.tostring() )
Trouble creating assert function
This is my assert function (it wont compile "error C2110: '+' : cannot add two pointers"): #define CHAR(x) #x template<typename T> inline void ASSERT(T x) { if(!x) { std::string s("ERROR! Assert " + CHAR(x) + " failed. In file " + __FILE__ + " at line " + __LINE__ + "."); std::wstring temp(s.length(), L' '); std::copy(s.begin(), s.end(), temp.begin()); getLogger().Write(temp); } } Any idea of how to fix it?
String Literals are easily reduced to char pointers, which cannot be added as you try to do with "ERROR! Assert " + CHAR(x) + " failed. In file ".... However, C++ has the handy feature of doing this automatically before compilation! (the preprocessor does this). Even better, it has a handy tool for making wide strings at compile time. So, you want: #define _T(x) L ## x #define CHAR(x) #x #define CHAR2(x) CHAR(x) #define ASSERT(x) ASSERT2(x, CHAR(x), __FILE__, CHAR2(__LINE__)) #define ASSERT2(x, t, f, l) \ if(!x) \ getLogger().Write(L"ERROR! Assert " _T(t) L" failed. In file " _T(f) L" at line " _T(l) L"."); http://ideone.com/0ibcj
The compiler error is quite clear; you are trying to apply the + operator to string literals. A quick way to fix it is enclosing the first string literal in std::string(). As #James McNellis pointed out, note that FILE and LINE will point to the file and line of the assert function declaration.
You cannot use the + operator to concatenate two char*s; you need printf or some sort of thing for that.
"ERROR! Assert " is a null-terminated, C-style string. You can't execute operator+ on it.
A few issues: Generally an assert should break into the debugger or dump if one is not attached. This will not. As already mentioned, your LINE and FILE require use in a macro You need a couple "helper" macros to get the strings working properly Try something along these lines: #define ASSERT_QUOTE_(x) #x #define ASSERT_QUOTE_(x) ASSERT_QUOTE_(x) #define MY_ASSERT(cond) \ if(cond) {} else { \ std::stringstream ss; \ ss << "ERROR! Assert " << ASSERT_QUOTE(cond) << " failed. In file " << __FILE__ << " at line " << __LINE__ << "."; \ getLogger().Write(ss.str()); \ } Be careful trying to use STL here however. I suggest you have your logger's Write() function take variable arguments and process them with printf() or perhaps boost::format