Is this commenting macro safe to use?

Started by
8 comments, last by Strewya 9 years, 11 months ago

Hello everyone.

I'm using a simple macro to comment out part of my code in release build, but i'm wondering if this could lead to some sort of problem, as i'm trying to cheat the precompiller into adding comments against the rule.

I use this to avoid writing duplicated code.

Basically, here is the macro


#if defined DEBUG
#define MACRO 
#else
#define MACRO );/ ## /
#endif

What it does is: If i'm in debug build, it does nothing. If i'm in release build, it close a function and comment the rest of the line.

The "/ ## /" part is needed to trick the compiler into thinking comment dont exist. But they do.

This is how i use the macro. (The code is simplified)


//Initialize a long list of interfaced classes into a map, allowing easy Factory access.
void Bar()
{
    //Assume each different letters is an interfaced class
    Foo(A0, A1 MACRO, A2, A3, A4);
    Foo(B0, B1 MACRO, B2, B3, B4);
    // Many Foo later...
    Foo(Z0, Z1 MACRO, Z2, Z3, Z4);
}

#if defined DEBUG
//Types don't really matter. Just the number of parameters is interesting.
void Foo(Type0, Type1, Type2, Type3, Type4)
{
    // Do something, in debug
}
#else
void Foo(Type0, Type1)
{
    // Do something, in release
}
#endif



As you can see, in release build, the compiler will see "Foo(A0, A1 );" as the comment will clear the rest of the line.
This way, i avoid writing this code:


#if defined DEBUG
Foo(A0, A1, A2, A3, A4);
Foo(B0, B1, B2, B3, B4);
// Many Foo later...
Foo(Z0, Z1, Z2, Z3, Z4);
#else
Foo(A0, A1);
Foo(B0, B1);
// Many Foo later...
Foo(Z0, Z1);
#endif

The reason i use it is to avoir writing duplicate code to avoid possible Copy/Paste errors.

As of writing this post, the macro work fine in either build, but i have this strange feeling i'm doing something cringe-worthy.

Am i really going overboard just to avoid writing duplicated code?

If so, is there other options?

Advertisement

It might be safe, but it's certainly horrifying. At the very least I would use a macro that calls Foo, and change the definition of that macro based on DEBUG or not. Something like:


#ifdef DEBUG
#define CALL_FOO(a, b, c, d, e) Foo(a, b, c, d, e)
#else
#define CALL_FOO(a, b, c, d, e) Foo(a, b)
#endif

But I would revisit why you're doing this in the first place and think if maybe there's something you can do with the implementation of Foo itself. Or your overall code. Not really enough info to work with....

SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.

I do it this ugly way:

#ifdef _DEBUG
#define DEBUG(a) a
#else
#define DEBUG(a)
#endif
 
#define COMMA ,
...
Foo(A0, A1 DEBUG(COMMA A2 COMMA A3 COMMA A4));
Foo(B0, B1 DEBUG(COMMA B2 COMMA B3 COMMA B4));

I must have some gaps in my knowledge, as i thought comments are removed before the precompiler processes the macros?

I know a macro like this wont work, because the compiler will see the two slashes as a comment and remove/ignore them:

#define MACRO //

But why/how does the one in the OP work?

#define MACRO / ## /

devstropo.blogspot.com - Random stuff about my gamedev hobby

I do it this ugly way:

Foo(A0, A1 DEBUG(COMMA A2 COMMA A3 COMMA A4));
Foo(B0, B1 DEBUG(COMMA B2 COMMA B3 COMMA B4));


Variadic-arg comments work well here:
#define DEBUG_ARGS(...) , __VA_ARGS__

Foo(A0, A1, DEBUG_ARGS(A2, A3, A4));

This is GCC/MinGW, but it's standardized in C++11 now.

But why/how does the one in the OP work?
#define MACRO / ## /


## takes two characters and combine them. It takes / and / and turns it into //.


By the way, I agree that passing arguments only while debugging is sometimes suspect and should warrant a second glance at what you are doing.


## takes two characters and combine them. It takes / and / and turns it into //.

Also known as token concatenation.

Hello to all my stalkers.


But why/how does the one in the OP work?

#define MACRO / ## /


This uses the concatenation operator "##" to insert a comment "//"

Edit: beaten by servant of the lord.

Keep in mind that using token pasting to synthesize a comment is not actually allowed by the standard, as it explicitly states comment removal occurs before macro processing - many compilers do it after, or both before and after, but some (like gcc) will outright reject the macro as it would expand to an illegal token after the macro processing phase:


error: pasting "/" and "/" does not give a valid preprocessing token

I would be very wary of using that macro on an unknown compiler, there is no telling what it would actually do.

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

As many already stated, i will revise the logic of my code to avoid using preprossesor-comments altogether. I already have an idea on how i might do that cleanly.

I understand now, the macro is not standard and should be avoided.

Thank you everyone.

Yes, i do realize token pasting is occuring, the question was more in line with "why are comments allowed to exist after the macro processing", since afaik they are removed before it.

Bacterius' answer is what i was after, thanks!

devstropo.blogspot.com - Random stuff about my gamedev hobby

This topic is closed to new replies.

Advertisement