Conditional code

J

John Smith

Lets say you have a function "debug printf" which works like printf but will
get left out if _DEBUG flag is not defined along with the strings which are
to be printed.

Now I defined this:

#ifdef _DEBUG
void dbgprintf(char *szFormat, ...);
#else
#define dbgprintf
#endif

This works fine but under some compilers eg. gcc it will give me a huge
bunch of warnings saying the statement has no effect. This is ofcourse true,
but I don't need to be reminded since this was the intention. Does any of
you have good ideas how I can improve the macro to stop the compiler from
giving this?

Thanks in advance.
-- John
 
D

Dave Moore

John Smith said:
Lets say you have a function "debug printf" which works like printf but will
get left out if _DEBUG flag is not defined along with the strings which are
to be printed.

Now I defined this:

#ifdef _DEBUG

Note that the above name is reserved for the implementation in ISO C++,
since it begins with an underscore and a capital letter. I guess this is ok
if you are making use of the compilers built-in debug flags, but I would
recommend against it. I always just define DEBUG or MY_DEBUG when I want to
do something like this example, and that works just fine.
void dbgprintf(char *szFormat, ...);
#else
#define dbgprintf
#endif

This works fine but under some compilers eg. gcc it will give me a huge
bunch of warnings saying the statement has no effect. This is ofcourse true,
but I don't need to be reminded since this was the intention. Does any of
you have good ideas how I can improve the macro to stop the compiler from
giving this?

I don't understand why you would see more than one error message ... are you
using include guards on your headers (I assume the above appears in exactly
one header file somewhere in your program.

In any case, why not just write:
// ...
#else
#define dbgprintf /**/

or something like that?

HTH,

Dave Moore
 
P

Pete Becker

John said:
This works fine but under some compilers eg. gcc it will give me a huge
bunch of warnings saying the statement has no effect.

Turn off the warning. You know better than some anonymous compiler
writer whether your code does what you meant it to do.
 
J

John Smith

Note that the above name is reserved for the implementation in ISO C++,
since it begins with an underscore and a capital letter. I guess this is ok
if you are making use of the compilers built-in debug flags, but I would
recommend against it. I always just define DEBUG or MY_DEBUG when I want to
do something like this example, and that works just fine.

Actually it's from Microsoft Compilers which sets that symbol. I just reused
it. The only thing I can say is that if people will have problems with it in
future, I won't be the only one.

I don't understand why you would see more than one error message ... are you
using include guards on your headers (I assume the above appears in exactly
one header file somewhere in your program.

Yes I have include guards. I'm sorry I wasn't telling the whole story. The
reason for having multiple warnings is just because I call dbgprintf()
multiple times in my code.
In any case, why not just write:
// ...
#else
#define dbgprintf /**/

or something like that?

Well I do that... and it works. But thats what gives warnings.
Assume we use it:

....
dbgprintf("test\n");

after the macro expansion it will look like:

("test\n");

and thus the code is not doing anything meaningful and I get the warning.

-- John
 
A

Andrey Tarasevich

John said:
Lets say you have a function "debug printf" which works like printf but will
get left out if _DEBUG flag is not defined along with the strings which are
to be printed.

Now I defined this:

#ifdef _DEBUG
void dbgprintf(char *szFormat, ...);
#else
#define dbgprintf
#endif

This works fine but under some compilers eg. gcc it will give me a huge
bunch of warnings saying the statement has no effect. This is ofcourse true,
but I don't need to be reminded since this was the intention. Does any of
you have good ideas how I can improve the macro to stop the compiler from
giving this?
...

I hope you understand that when '_DEBUG' is not defined the statement

dbgprintf("%d %d %d", a, b, c);

turns (after preprocessing) into

("%d %d %d", a, b, c);

i.e. it is not completely left out. This is a completely different
statement with completely different semantics. In many cases it will
have no effect (which is what the compiler is trying to tell you), but
is it actually what you wanted to do?
 
J

John Smith

I hope you understand that when '_DEBUG' is not defined the statement
dbgprintf("%d %d %d", a, b, c);

turns (after preprocessing) into

("%d %d %d", a, b, c);

i.e. it is not completely left out. This is a completely different
statement with completely different semantics. In many cases it will
have no effect (which is what the compiler is trying to tell you), but
is it actually what you wanted to do?

Actually yes it is. I'd rather get it removed all together. The idea is to
print out when in debug mode and leave the code out in release mode
(including the string to print).
Another guy suggested to make a dummy function which does nothing but it's
not suitable to me since the strings are still left in.

if the function had known arguments I could just make a dummy like:
#define dbgprintf(a,b,c)

but since it uses varargs I'm not sure how to create such a macro which
satisfies it.

The alternative would be like manually declare each line:

#ifdef _DEBUG
printf("we are in debug mode now\n");
#endif

But this takes 3 lines of code whereas dbgprintf() only takes 1.

Any ideas?

Thanks.
-- John
 
E

Efrat Regev

John Smith said:
Lets say you have a function "debug printf" which works like printf but will
get left out if _DEBUG flag is not defined along with the strings which are
to be printed.

Now I defined this:

#ifdef _DEBUG
void dbgprintf(char *szFormat, ...);
#else
#define dbgprintf
#endif

1. You could use in your code

dbgprintf("Print this string");

and define

#ifdef _DEBUG
void dbgprintf(whatever_arguments ...)
{
printf(...
}
#else // #ifdef _DEBUG
void dbgprintf(whatever_arguments ...)
{
// Do nothing.
}
#endif // #ifdef _DEBUG

2. Personally, I'm apprehensive about this approach at all. Consider the
following
dbgprintf("%d", my_terribly_expensive_operation());
or
dbgprintf("%d", my_operation_with_various_side_effects());

Then the compiler would call my_terribly_expensive_operation() or
my_operation_with_various_side_effects() even in release mode - probably not
what I want.
So I usually define dbgprintf as a macro itsel - this way the compiler can
eleminate its arguments completely.

3. Another matter which is possibly personal taste - it might be better to
distinguish between debug and trace: the first checks internal invariants;
the second outputs diagnostic information. Personally, I think these should
be orthogonal. There are cases where I find bugs in release mode only (e.g.,
because of thread races, which debug mode can change entirely). At the very
least, I usually try to have orthogonal debug and trace macros.
 
D

Dave Moore

Well I do that... and it works. But thats what gives warnings.
Assume we use it:

...
dbgprintf("test\n");

after the macro expansion it will look like:

("test\n");

ROFL .. I was wondering what on earth you were talking about until I looked
closely at my earlier suggestion .. what I meant was:

#else
#define dbgprintf //

that way whatever the args of dbgprintf are, they will be turned into a
comment. I knew I had used comments previously to deal with this, but I
didn't remember exactly how. Sorry for the confusion.

HTH,

Dave Moore
 
A

Andrey Tarasevich

John said:
Actually yes it is. I'd rather get it removed all together. The idea is to
print out when in debug mode and leave the code out in release mode
(including the string to print).

There is another rather well-known approach. Define your macro as

#ifdef _DEBUG
void dbgprintf_(char *szFormat, ...);
#define dbgprintf(p) dbgprintf_ p
#else
#define dbgprintf(p)
#endif

and use it as follows

dbgprintf(("%d %d %d\n", a, b, c));

(note the double parenthesis). In this case everything will be left out
in non-debug version, but you have to use '(())', which makes it look a
little inelegant.
 
A

Andrey Tarasevich

Dave said:
ROFL .. I was wondering what on earth you were talking about until I looked
closely at my earlier suggestion .. what I meant was:

#else
#define dbgprintf //

that way whatever the args of dbgprintf are, they will be turned into a
comment. I knew I had used comments previously to deal with this, but I
didn't remember exactly how. Sorry for the confusion.
...

This might work with some compilers, but won't work in general. In C++
the comments are fully processed (and replaced with whitespace) before
the preprocessor has a chance to do its thing. The compiler is free to
assume that preprocessor doesn't generate any new comments.
 
J

John Smith

ROFL .. I was wondering what on earth you were talking about until I
looked
closely at my earlier suggestion .. what I meant was:

#else
#define dbgprintf //

Good idea but unfortunatly gcc wasn't fooled by it. It just ignores the
comment and continues with the warnings.
Too bad.

-- John
 
J

John Smith

Turn off the warning. You know better than some anonymous compiler
writer whether your code does what you meant it to do.
Yes that will be my last way out if I don't find a better way. As suggested
in other threads the codes isn't removed completely so theres still room for
alternate improvements.

Unfortunatly gcc doesn't spit out error codes like some other compilers
does, so it's a little harder to be sure you turn off a specific warning
message.

-- John
 
H

Heinz Ozwirk

Dave Moore said:
#define dbgprintf //

that way whatever the args of dbgprintf are, they will be turned into a
comment.

Not a good idea. Even if it would work, it would only work with single line statements. Something like

dbgprintf("....",
arg1,
arg2,
//...
);

would most likely cause a compilation error.

Heinz
 
D

Dave Moore

Dave Moore said:
#define dbgprintf //

that way whatever the args of dbgprintf are, they will be turned into a
comment.

Not a good idea. Even if it would work, it would only work with single line
statements. Something like

dbgprintf("....",
arg1,
arg2,
//...
);

would most likely cause a compilation error.

Heinz

Well .. I never used my homemade debug utility that way so it never came up
.... what worries me more is that now it doesn't work properly anymore, at
least not on g++. I can't remember for sure what platform I initially used
the trick on (Metrowerks I think). Bummer ... I liked it because it was so
simple and didn't rely on any "macro magic", which I find frightening. I
guess I will have to implement one of the other strategies posted here if I
have a need for such a "trick" again in the future.

Thanks for straightening me out y'all.

Dave Moore
 
H

harald.deischinger

What about this version:

#ifdef _DEBUG
statid void debugprintf_(const char *, ...) {}
#define debugprintf debugprintf_
#endif

So in debug mode all calls to debugprintf will be translated to
debugprintf_, and that function then does nothing.

This method has the advantage/disadvantage that all the arguments to
debugprintf will always be evaluated. This is good because it saves you
from error caused by missing side effects of arguments no evaluated in
the release version, but is also bad because you waste cpu time in the
release mode.

harald
 
?

=?ISO-8859-15?Q?Juli=E1n?= Albo

John said:
Lets say you have a function "debug printf" which works like printf but
will get left out if _DEBUG flag is not defined along with the strings
which are to be printed.

Now I defined this:

#ifdef _DEBUG
void dbgprintf(char *szFormat, ...);
#else
#define dbgprintf
#endif

This works fine but under some compilers eg. gcc it will give me a huge
bunch of warnings saying the statement has no effect. This is ofcourse

You can use something like this:

#else
inline void dbgprintf_do_nothing_version_with_ugly_name (char *, ...) { }
#define dbgprintf dgbprintf_do_nothing_version_with_ugly_name
#endif
 

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
474,201
Messages
2,571,048
Members
47,647
Latest member
NelleMacy9

Latest Threads

Top