Custom ASSERT macro

S

Stephen Tyndall

I know the preprocessor is evil, but I'd like to know what's going on in the
following code.

The problem is when the num variable is used in the ASSERT macro inside
main(). When running the code, I get the following error from Visual
C++.NET 2003:

warning C4806: '==' : unsafe operation: no value of type 'bool' promoted to
type 'int' can equal the given constant

#define DEBUG 2

#include <iostream>

using namespace std;

#if DEBUG == 0

#define ASSERT(n)

#elif DEBUG == 1

#define ASSERT(n) if(!n) { cout << #n << " failed" << endl; }

#elif DEBUG == 2

#define ASSERT(n) \

if(!n) { \

cout << #n << " failed on line " << __LINE__ << endl; \

} \

else { \

cout << #n << " passed on line " << __LINE__ << endl; \

}

#endif

int main() {

bool flag = true;

int num = 5;

ASSERT(flag == true);

ASSERT(flag == false);

// when I change the below to ASSERT((num == 5)); it works perfectly.

// what's wrong with the version below?

ASSERT(num == 5);

return 0;

}

Thanks in advance for your help.
 
A

Artie Gold

Stephen said:
I know the preprocessor is evil, but I'd like to know what's going on in the
following code.

The problem is when the num variable is used in the ASSERT macro inside
main(). When running the code, I get the following error from Visual
C++.NET 2003:

warning C4806: '==' : unsafe operation: no value of type 'bool' promoted to
type 'int' can equal the given constant

#define DEBUG 2

#include <iostream>

using namespace std;

#if DEBUG == 0

#define ASSERT(n)

#elif DEBUG == 1

#define ASSERT(n) if(!n) { cout << #n << " failed" << endl; }

#elif DEBUG == 2

#define ASSERT(n) \

if(!n) { \

cout << #n << " failed on line " << __LINE__ << endl; \

} \

else { \

cout << #n << " passed on line " << __LINE__ << endl; \

}

#endif

int main() {

bool flag = true;

int num = 5;

ASSERT(flag == true);

ASSERT(flag == false);

// when I change the below to ASSERT((num == 5)); it works perfectly.

// what's wrong with the version below?

ASSERT(num == 5);

Think about it. What does the line above expand to?
return 0;

}

HTH,
--ag
 
A

Alf P. Steinbach

* Stephen Tyndall:
I know the preprocessor is evil, but I'd like to know what's going on in the
following code.

The problem is when the num variable is used in the ASSERT macro inside
main(). When running the code, I get the following error from Visual
C++.NET 2003:

warning C4806: '==' : unsafe operation: no value of type 'bool' promoted to
type 'int' can equal the given constant

#define DEBUG 2

#include <iostream>

using namespace std;

#if DEBUG == 0

#define ASSERT(n)

#elif DEBUG == 1

#define ASSERT(n) if(!n) { cout << #n << " failed" << endl; }

#elif DEBUG == 2

#define ASSERT(n) \

if(!n) { \

cout << #n << " failed on line " << __LINE__ << endl; \

} \

else { \

cout << #n << " passed on line " << __LINE__ << endl; \

}

#endif

int main() {

bool flag = true;

int num = 5;

ASSERT(flag == true);

ASSERT(flag == false);

// when I change the below to ASSERT((num == 5)); it works perfectly.

// what's wrong with the version below?

ASSERT(num == 5);

return 0;

}

Check out operator precedence. How is the following parsed?

cout << flag == true << " failed." << endl;

I'm surprised it even compiles, but it's late and I don't want
to think about why it could compile right now...

Hth.
 
A

Alf P. Steinbach

* Alf P. Steinbach:
* Stephen Tyndall:

Check out operator precedence. How is the following parsed?

cout << flag == true << " failed." << endl;

I'm surprised it even compiles, but it's late and I don't want
to think about why it could compile right now...

Yes it's late, it's late late late, and me Very Sleepy (TM).

Of course it's not expanded like that; you have # in there.

It's the 'if' condition expansion of the last assert that's
the problem, as Artie Gold pointed out.
 
S

Stephen Tyndall

Artie Gold said:
Think about it. What does the line above expand to?

Oh. I should have realized that, especially with the parentheses thing;
sorry, I'm new at this. Thanks for the help, and the quick response.
 
I

Ivan Vecerina

Stephen Tyndall said:
#define ASSERT(n) if(!n) { cout << #n << " failed" << endl; }

Besides the missing parentheses, this definition of ASSERT has another
serious problems.
When defining statement macros, you should always think of constructs such
as:
Consider:
if( b )
ASSERT( a );
else
{ /* do stuff */ }
Here the extra ';' after the { } of the expanded macro will prevent 'else'
from being interpreted correctly.
A common solution to this issue is to enclose the contents of the macro in a
do...while(false) block:
#define ASSERT(n) do{ if(!n) { cout << #n << " failed" << endl; } }
while(false)

hth
Ivan
 
I

Ivan Vecerina

#define ASSERT(n) do{ if(!n) { cout << #n << " failed" << endl; } }
Of course this should be (without the copy-pasted error):
#define ASSERT(n) do{ if(!(n)) { cout << #n << " failed" << endl; } }


Actually, to avoid requiring client code to include <iostream>
(and maybe also to reduce code bloat and possibly improve performance),
I usually prefer to implement ASSERT as something like:

extern void assert_notify_failure(const char* str); // may also take
__FILE__ & __LINE__
#define ASSERT(n) if(n){}else assert_notify_failure(#n)
//here the if+else trick is an alternative to do..while(false)

//then in some implementation file:
#include <iostream>
void assert_notify_failure(const char* str)
{
std::cerr << str << " failed" << std::endl;
}


That's it this time ;)
Ivan
 
S

Stephen Tyndall

Ivan Vecerina said:
Of course this should be (without the copy-pasted error):
#define ASSERT(n) do{ if(!(n)) { cout << #n << " failed" << endl; } }


Actually, to avoid requiring client code to include <iostream>
(and maybe also to reduce code bloat and possibly improve performance),
I usually prefer to implement ASSERT as something like:

extern void assert_notify_failure(const char* str); // may also take
__FILE__ & __LINE__
#define ASSERT(n) if(n){}else assert_notify_failure(#n)
//here the if+else trick is an alternative to do..while(false)

//then in some implementation file:
#include <iostream>
void assert_notify_failure(const char* str)
{
std::cerr << str << " failed" << std::endl;
}

I was pretty sure the macro I posted wasn't that good; it's from a book I'm
learning from. I don't know a lot about that kind of thing yet but it felt
kind of sloppy somehow.

Thanks for the reply. I'll cut and paste your version of ASSERT for later
use.
 

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

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top