Can I override assert macro?

Pages: 12
I want to add a message in assert like static_assert.
It's possible?
Yes, it is possible, though it requires a bit of a "hack" to extend the functionality.

https://en.cppreference.com/w/cpp/error/assert
We can do this: assert( (i>9) && "message: value of i must be greater than 9" ) ;
Last edited on
Thank you, guys!
JLBorges, I like your usage better than what I found at cppreference, with the #define.

In Visual Studio 2017/2019 using the comma operator instead of && works.
assert(i > 9, "message: value of i must be greater than 9");

Not in Code::Blocks, though. So I'd gather other compilers (without actually checking) won't like the comma operator as well.

I like your more portable, easier to remember and type, solution. :)

@furry guy, it presumably doesn't really "work" in VS either since it will always be true (and therefore never abort).

The reason you get a compilation error with gcc is because assert is a macro (in gcc at least) and therefore you would need to put parens around the whole thing if you really wanted to pass in a comma.
Last edited on
@dutch, I tested it in debug and release mode and it does work using the comma operator. Debug mode the assert activates, release mode it doesn't.

1
2
3
4
5
6
7
8
9
#include <iostream>
#include <cassert>

int main()
{
   int i { 8 };

   assert(i > 9, "message: value of i must be greater than 9");
}


Visual Studio in debug mode pops up a C++ Runtime Library debug error dialog!

I understand why enclosing in parentheses is needed, the cppreference example for instance, it just seems to be a tad bit excessive when there are other ways to do it without the comma operator.

LJBorges' solution is better IMO -- more elegant -- since it looks to work no matter what the compiler, and it doesn't require extra parentheses. Or the kludginess of a #define.
I tested it in debug and release mode and it does work using the comma operator. Debug mode the assert activates, release mode it doesn't.

Interesting. I wonder how that works? The value of the comma operator is the value of the rhs, and that's a non-null char pointer, which should evaluate to true.
I am not someone that delves into the nitty-gritty details of how things are implemented, I just use what the language offers.

I almost didn't test using the comma operator in GCC/MinGW. I presumed it worked without testing it. BIG MISTAKE I routinely make, being a self-taught hobbyist programmer.

After seeing JLBorges' use of && I smelled "wrong code" with the comma operator in VS, so I did test it. And found out it looks to be a quirk that is within the implementation of VS.

Not surprising, really, considering MS doesn't implement the C11 standard, except half-heartedly to support implementing the various C++ standards from C++11 and later.

When VS2019 was first released using asserts had problems since the IDE didn't set the command line /D flag to DEBUG or NDEBUG at all. Something VS 2017 did.

I submitted a defect report to MS, was informed they couldn't duplicate the defect.

Yet soon afterwards the command line flag was part of the command line settings in the project's property pages. Heh.
Interesting. Using the comma operator and swapping the comparison and the message completely blows up the assertion. No assertion, period!

assert("message: value of i must be greater than 9", i > 9);

Using && instead of , and asserts work again. In VS or Code::Blocks.

Curiouser and curiouser.

The comma operator working with asserts is a quirky bug in VS, no way around that.
@furry guy, That is interesting. Thanks for checking it out.
Makes me wonder (just a little bit) how MS implements assert now.

Not that I'd understand the code. :)
https://en.wikipedia.org/wiki/Assert.h
Although Microsoft has its own "assert with message" macro, there is no standarized variant of assert() that includes an error message.


So if we follow this... <cassert> simply #includes <assert.h>...
assert.h is located (at least for me) inside C:\Program Files (x86)\Windows Kits\10\Include\{version}\ucrt

assert.h contents:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifdef NDEBUG

    #define assert(expression) ((void)0)

#else

    _ACRTIMP void __cdecl _wassert(
        _In_z_ wchar_t const* _Message,
        _In_z_ wchar_t const* _File,
        _In_   unsigned       _Line
        );

    #define assert(expression) (void)(                                                       \
            (!!(expression)) ||                                                              \
            (_wassert(_CRT_WIDE(#expression), _CRT_WIDE(__FILE__), (unsigned)(__LINE__)), 0) \
        )

#endif 


So yeah, Visual Studio uses its own special implementation (_wassert).

Last edited on
But it's still a macro, and this part needs to be false in order to call _wassert: (!!(expression))

1
2
3
4
5
6
#include <iostream>
int main() {
    int i = 8;
    (!!(i > 9, "message: value of i must be greater than 9"))
    || std::cout << "failed!\n";        // doesn't print
}

Also, I wonder if it acts differently when compiled as C++ or C?
Yeah.. wait. I have no idea. The assert macro doesn't even compile for me using GCC, because it says that the macro only has 1 parameter, but I'm trying to pass in 2.
Due to conditional compilation, it can be hard to trace what is actually part of the code in header files (as I'm sure you know). Maybe C++ and C mode compile different code and what you've posted is C-mode code.

I don't have windows so I can't test if there are differences compiling for C or C++. (I'm assuming furry guy compiled as C++.(?))
@dutch, you are correct. C++ compiled.

I am not all that knowledgeable about C, so wouldn't know where to start for a simple assert test in C.

Well, I tried a simple C test:

1
2
3
4
5
6
7
8
#include <assert.h>

int main()
{
   int i = 8;

   assert(i > 9, "message: value of i must be greater than 9");
}


This also works in C:
1
2
3
4
5
6
7
8
#include <assert.h>

int main()
{
   int i = 8;

   assert("message: value of i must be greater than 9" && (i > 9));
}
So if we follow this... <cassert> simply #includes <assert.h>...
assert.h is located (at least for me) inside C:\Program Files (x86)\Windows Kits\10\Include\{version}\ucrt

Yeah, the Windows Kits include C headers. The C++ headers are located elsewhere, I installed VS 2019 on a different drive.

On my system it is D:\Programming\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.24.28314\include

Holy Frack!
Did you mean to use a comma in the second one? (We know that && always works.)
And are you definitely compiling as C? You need to change a setting somewhere, if I remember correctly.

How about these:
1
2
   assert(0, 1);
   assert(0, "hello", "world");

VS uses the file extension, .c or .cpp, to determine how to compile it.

Trying to compile C source code with a variable being initialized with C++ uniform initialization int i { 8 }; craps out:

Error (active)	E0065	expected a ';'	Project2	C:\Programming\My Projects 2019\Project2\Project2\Source.c	5	
Error	C2143	syntax error: missing ';' before '{'	Project2	C:\Programming\My Projects 2019\Project2\Project2\Source.c	5	
Error	C2143	syntax error: missing ';' before '}'	Project2	C:\Programming\My Projects 2019\Project2\Project2\Source.c	5	

And no, I intended to use && in the second snippet. To see if the C compiler might have problems.
Pages: 12