tags:

views:

128

answers:

3

I have the following macro:

#define IF_TRACE_ENABLED(level)  if (IsTraceEnabled(level))

The user code should look following:

IF_TRACE_ENABLED(LEVEL1)
{
    ... some very smart code
}

The emphasis here on curly brackets - I want to prevent "if" from macro to "eat" other code:

if (...)
   IF_TRACE_ENABLED(LEVEL1)
      printf(....);
else
   bla bla bla

In this example IF_TRACE_ENABLED "eats" else block.

Is there way to enforce user code not compile without curly brakes or there are other to define the macro to achieve the safety?

A: 

This should work, but you'll have the pass the contents of the if block as an argument to the macro as well:

#define IF_TRACE_ENABLED(level,content)  { if (IsTraceEnabled(level)) {content} }
Kedar Soparkar
This is not necessary printf(...). This could be any code that should be evaluated only when macro condition is true.
dimba
You should add a block around content.
Ronny
@Ronny - this is what I want to enforce user, so if he forgets to do it, the compilation will fail
dimba
@crypto - passing content to macro could be complicated and will influence user - we need be careful with commas in content not to be interpreted as macro argument separator, what if I want comment line to be part of comment.
dimba
@dimba it wouldn't fail this way
Ronny
+2  A: 

You could try this:

#define IF_TRACE_ENABLED(level) do { if(IsTraceEnabled(level)) {
#define END_TRACE_ENABLED } } while(0);

I don't think there's any way to "enforce" good syntax from only the opening line of the macro. You will need to use two.

EDIT

I've added an extra pair of braces inside the macro to avoid all ambiguity.

In response to the comment, this macro is meant to be used like this:

IF_TRACE_ENABLED(LEVEL1)
    printf("Trace\n");
END_TRACE_ENABLED

Not as a statement. For the record, I think this is an abuse of the preprocessor and nobody should do this at all. What's wrong with just writing it out, bracketed with #ifdef DEBUG if necessary.

ptomato
The only thing I don't like in the solution is indentation of the block between stat and stop macros - your editor won't indent it.
dimba
Kedar Soparkar
@ptmato - there's something in what @crypto says. do/while is used to enfore macro to look like normal function, by that that he's enforced to use ";" in the end. So ";" in the end of macro is redundant.Any way we don't ";" since the macro doesn't look like a function call
dimba
@dimba, this isn't meant to be used with a semicolon at the end. See edit.
ptomato
@crypto, probably. I just thought this would be less likely to have a corner case where it didn't work.
ptomato
+10  A: 

This doesn't force the user of the macro to use braces, but it will prevent an else clause from being unintentionally eaten:

#define IF_TRACE_ENABLED(level)  if (!IsTraceEnabled(level)) {} else 

A side note: braces around the printf() in the second example of the question wouldn't have fixed the problem - the else associated with bla bla bla would still be bound to the if statement in the macro.

Michael Burr
Trying and failing to come up with a way this could backfire. +1
Chris Lutz
Where is content of "if" block is passed?
dimba
in the else block; nice answer!
Kedar Soparkar
+1, clean and simple as it should be
Patrick
@dimba: The test has been inverted, so that the contents of the block are executed by the `else`.
caf
@Chris Lutz: it fails if the user decided they wanted an else i.e. if they wanted `IF_TRACE_ENABLED(level) ... else { ... }`
JeremyP
@JeremyP: that's probably an unlikely use case, and I'd probably argue that instead of a failure, it's 'as designed'. If there is a use case for supporting an else clause, another macro or set of macros can be created to support it.
Michael Burr
@Michael Burr: there's not really a use case for this monstrosity in the first place. C has a perfectly good if control structure without creating new and broken ones.
JeremyP