Stop using assert macro

I

Immortal Nephi

I write custom assertion. The custom assertion is no longer to use
macros. The macros replacement is to use inline function.
Please comment which macros or inline function is better. I don’t
like to place __FILE__ and __LINE__ in inline function’s parameters.

#define DEBUG

#ifdef DEBUG
inline void cassert( bool expr, const char* file, int line, const
char* message )
{
if( !expr )
std::cout << file << "(" << line << ") : Assert failed - Expression:
" << message << std::endl;
}
#else
inline void cassert( bool expr, const char* file, int line, const
char* message ) {}
#endif

#ifdef DEBUG
#define assert( expr, message ) \
if( !expr ) \
std::cout << __FILE__ << "(" << __LINE__ << ") : Assert failed -
Expression: " << message << std::endl;
#else
#define assert( expr, message ) ( ( void ) 0 )
#endif

int main()
{
int a = 5;
cassert( 10 < a, __FILE__, __LINE__, "10 < 5" );
assert( 10 < a, "10 < 5" );

return 0;
}
 
F

Fred

        I write custom assertion.  The custom assertion is no longer to use
macros.  The macros replacement is to use inline function.
        Please comment which macros or inline function is better.  I don’t
like to place __FILE__ and __LINE__ in inline function’s parameters.

#define DEBUG

#ifdef DEBUG
inline void cassert( bool expr, const char* file, int line, const
char* message )
{
        if( !expr )
                std::cout << file << "(" << line << ") : Assert failed - Expression:
" << message << std::endl;}

#else
inline void cassert( bool expr, const char* file, int line, const
char* message ) {}
#endif

#ifdef DEBUG
#define assert( expr, message ) \
        if( !expr ) \
                std::cout << __FILE__ << "(" << __LINE__ << ") : Assert failed -
Expression: " << message << std::endl;
#else
#define assert( expr, message ) ( ( void ) 0 )
#endif

#else
#define assert( expr, message )
#endif

The above #else block causes the preprocessor to put NOTHING in.
So the compiler never sees anything about the assert.

With the inline method, the compiler still sees every assert,
and the optimizer has to figure out each time it sees an assert
that there is really nothing there.
 
V

Victor Bazarov

Immortal said:
I write custom assertion.
Why?

> The custom assertion is no longer to use
macros. The macros replacement is to use inline function.
Why?

Please comment which macros or inline function is better. I don’t
like to place __FILE__ and __LINE__ in inline function’s parameters.

#define DEBUG

#ifdef DEBUG
inline void cassert( bool expr, const char* file, int line, const
char* message )
{
if( !expr )
std::cout << file << "(" << line << ") : Assert failed - Expression:
" << message << std::endl;
}
#else
inline void cassert( bool expr, const char* file, int line, const
char* message ) {}
#endif

#ifdef DEBUG
#define assert( expr, message ) \
if( !expr ) \
std::cout << __FILE__ << "(" << __LINE__ << ") : Assert failed -
Expression: " << message << std::endl;
#else
#define assert( expr, message ) ( ( void ) 0 )
#endif

int main()
{
int a = 5;
cassert( 10 < a, __FILE__, __LINE__, "10 < 5" );
assert( 10 < a, "10 < 5" );

Why do you have the text with "5" instead of "a"? Kinda weird to have
the reported expression different from the one you're checking.
return 0;
}

None is better. Better is to use macros and let them do their job.

To stop using macros is a noble goal (perhaps), but what if you have two
different assertions both have the control condition 10 < a, and both
have the same expression text "10 < a", but in two different files or on
two different lines of the same file? You *have to* use __FILE__ and
__LINE__ in that case, don't you? If you don't like to manually insert
those in your source, then you need to use macros which can do it for
you. Not to mention that you have to write your expression twice, which
is the source of maintenance problems.

Patient: "Doctor, when I stop using macros
I don't get automatic __FILE__ and
__LINE__ for my assertion checks."

Doctor: "Well... Don't stop using macros!"

V
 
J

John H.

        Please comment which macros or inline function is better.

There are at least a couple advantages to the macro version of assert:
- You can easily change between DEBUG and and not debug behavior on a
per use basis. With the function implementation, the behavior is
usually fixed when the assert header is included.
- In the macro version you can have it skip the evaluation of the
expression if not in debug mode. With your function implementation,
the expression will always be evaluated (unless the optimizer takes
some steps to avoid it). This is what Fred was saying.

There was a recent thread related to this:
http://groups.google.com/group/comp.lang.c++/browse_thread/thread/2c3eb92c202cae32
 
J

James Kanze


To make it harder to use, and less efficient.
Why do you have the text with "5" instead of "a"? Kinda weird
to have the reported expression different from the one you're
checking.

Another advantage of not using macros: you have an additional
possibility of confusing the maintenance programmer.
None is better. Better is to use macros and let them do their job.
To stop using macros is a noble goal (perhaps), but what if
you have two different assertions both have the control
condition 10 < a, and both have the same expression text "10 <
a", but in two different files or on two different lines of
the same file? You *have to* use __FILE__ and __LINE__ in
that case, don't you? If you don't like to manually insert
those in your source, then you need to use macros which can do
it for you. Not to mention that you have to write your
expression twice, which is the source of maintenance problems.
Patient: "Doctor, when I stop using macros
I don't get automatic __FILE__ and
__LINE__ for my assertion checks."
Doctor: "Well... Don't stop using macros!"

I might add that you can #undef and then #define a macro again.
This is an important feature of assert: it can be defined
differently in different parts of a source file.
 
I

Immortal Nephi

To make it harder to use, and less efficient.

Why do you say less efficient? I do not use macros and I write
custom assert function instead. I use debugger to test it before
debugger reports no bugs in assert function if I make mistakes to
write custom assert function. I copy and paste assert function into
macros. I do not need to use debugger. The assert function helps me
to track all the variables and correct out of ranges.
Another advantage of not using macros: you have an additional
possibility of confusing the maintenance programmer.

Maybe not.
I might add that you can #undef and then #define a macro again.
This is an important feature of assert: it can be defined
differently in different parts of a source file.

I suggest below.

#ifdef DEBUG
inline void cassert( bool expr, const char* file, int line, const
char* message )
{
if( !expr )
std::cout << file << "(" << line << ") : Assert failed
- Expression:
" << message << std::endl;
}

#define CASSERT( expr, message ) cassert( expr, __FILE__, __LINE__,
message )

#else
#define CASSERT( expr, message ) ( ( void ) 0 )
#endif

int main()
{
int a = 5;
CASSERT( 10 < 5, "10 < 5" << a << "." );

return 0;
}

I think that custom assert function is flexible. You do not need to
put inline function "cassert( expr, __FILE__, __LINE__, message )" in
the main function body. You can use CASSERT macro instead. CASSERT
macro does the job to invoke cassert(...). You can only write expr
and message. You don't need to put __FILE__ and __LINE__ in the main
function body.
If DEBUG is turned off, C++ Compiler ignores or skips CASSERT and it
does the job to do optimization.
Do you notice?

CASSERT( 10 < 5, "10 < 5" << a << "." );

You can modify message and add variables to it. Flexible? You don't
have to use operator # & ## macros to expand text.
 
I

Ian Collins

I suggest below.

#ifdef DEBUG
inline void cassert( bool expr, const char* file, int line, const
char* message )
{
if( !expr )
std::cout<< file<< "("<< line<< ") : Assert failed
- Expression:
"<< message<< std::endl;
}

#define CASSERT( expr, message ) cassert( expr, __FILE__, __LINE__,
message )

#else
#define CASSERT( expr, message ) ( ( void ) 0 )
#endif

int main()
{
int a = 5;
CASSERT( 10< 5, "10< 5"<< a<< "." );

return 0;
}

I think that custom assert function is flexible. You do not need to
put inline function "cassert( expr, __FILE__, __LINE__, message )" in
the main function body. You can use CASSERT macro instead. CASSERT
macro does the job to invoke cassert(...). You can only write expr
and message. You don't need to put __FILE__ and __LINE__ in the main
function body.
If DEBUG is turned off, C++ Compiler ignores or skips CASSERT and it
does the job to do optimization.
Do you notice?

CASSERT( 10< 5, "10< 5"<< a<< "." );

You can modify message and add variables to it. Flexible? You don't
have to use operator #& ## macros to expand text.

So what you are really doing is swapping the standard assert macro for
your CASSERT macro. What's the point?
 
I

Ian Collins

Without wading into the discussion too much, I've certainly seen the odd
article talking about why you might want to do that. If you can access
it somehow (you can see a bit of it via Google Books), one such article is:

"Squeezing More Out of Assert", Steve Rabin, in Game Programming Gems 1.

One of the ideas there is to bring up a custom dialog with "Continue" /
"Break" / "Ignore Always" options before breaking to the debugger -
whilst I guess it might be argued that if the assert fails it's because
something's seriously wrong and needs fixing, it can clearly be useful
in the short term to keep running the failing program for debugging
purposes.

Yes, but you can do that just as well by redefining assert, it is a
macro after all!
 
I

Ian Collins

Well sure :) Maybe I misunderstood the point of your previous post in
that case. I thought you were questioning whether there was any merit in
defining a custom assert was all - and I remembered seeing something
about it which seemed of interest.

I thought so. I do use a custom assert for unit test code (so I can
tell it to expect a failure and not abort). But I do that by
interposing the function the macro calls.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top