Another macro question

  • Thread starter Edward Rutherford
  • Start date
E

Edward Rutherford

I am porting a codebase that makes extensive use of the following
construction:

#define CAT(a,b) a##b
#define COMMENT CAT(/,/)
COMMENT This is a comment

It works as intended on the original Windows system, but not on the
target compiler, which claims that comments should not be processed after
macro expansion. So I have an odd situation where the preprocessor output
is as intended and is compilable, whereas the original file is not.

What is the truth, according to the standards? If it is invalid, can
anyone suggest an alternative definition for the COMMENT macro that will
achieve the same effect?

Thanks.
 
K

Keith Thompson

Edward Rutherford said:
I am porting a codebase that makes extensive use of the following
construction:

#define CAT(a,b) a##b
#define COMMENT CAT(/,/)
COMMENT This is a comment

It works as intended on the original Windows system, but not on the
target compiler, which claims that comments should not be processed after
macro expansion. So I have an odd situation where the preprocessor output
is as intended and is compilable, whereas the original file is not.

What is the truth, according to the standards? If it is invalid, can
anyone suggest an alternative definition for the COMMENT macro that will
achieve the same effect?

The target compiler is correct. Comments are replaced by space
characters in translation phase 3; macros invocations are expanded
in phase 4 (C99 5.1.1.2). By the time the "//" is produced, it
shouldn't be recognized as a comment delimiter.

I don't believe there's any way for a macro to expand to a comment
delimiter.

Why not just use "//"?

Or, if you must use "COMMENT" for some reason, modify your build
procedure so each source file is filtered through something that
replaces "COMMENT" by "//" (watch out for occurrences of "COMMENT"
in string literals, header names, and, in principle, character
constants).
 
E

Edward Rutherford

Keith said:
The target compiler is correct. Comments are replaced by space
characters in translation phase 3; macros invocations are expanded in
phase 4 (C99 5.1.1.2). By the time the "//" is produced, it shouldn't
be recognized as a comment delimiter.

I don't believe there's any way for a macro to expand to a comment
delimiter.

Why not just use "//"?

Or, if you must use "COMMENT" for some reason, modify your build
procedure so each source file is filtered through something that
replaces "COMMENT" by "//" (watch out for occurrences of "COMMENT" in
string literals, header names, and, in principle, character constants).

Keith.

Rereading my original post I see that it may have been misleading as to
how this macro is used.

The idea is that it provides a way to selectively comment out individual
lines of code: in effect, it is to single lines what
#if DEBUGMODE...#endif is to blocks.

So an example of a COMMENT line might be
COMMENT logger_write(LOG_DEBUG2, "Entering foo function, x=%d", x);

The COMMENT macro can either be defined as in my original post (to
exclude the line), or as a null macro (to include the line).

One possibility would be to look for all occurrences of COMMENT lines and
surround them by #if...#endif blocks. However, this would clutter the
code and make it much harder to read.

Is there a portable, standards-compliant way to define COMMENT to achieve
the desired effect?

/EPR
 
K

Keith Thompson

Edward Rutherford said:
Rereading my original post I see that it may have been misleading as to
how this macro is used.

The idea is that it provides a way to selectively comment out individual
lines of code: in effect, it is to single lines what
#if DEBUGMODE...#endif is to blocks.

So an example of a COMMENT line might be
COMMENT logger_write(LOG_DEBUG2, "Entering foo function, x=%d", x);

The COMMENT macro can either be defined as in my original post (to
exclude the line), or as a null macro (to include the line).

One possibility would be to look for all occurrences of COMMENT lines and
surround them by #if...#endif blocks. However, this would clutter the
code and make it much harder to read.

Is there a portable, standards-compliant way to define COMMENT to achieve
the desired effect?

So you want something like

#if DEBUGMODE
#define COMMENT //
#else
#define COMMENT
#endif

(except that it actually works), right?

I don't think you can *quite* do that. What you can do is:

#if DEBUGMODE
#define COMMENT(arg) arg
#else
#define COMMENT(arg)
#endif

Then your COMMENT line would have to look like:

COMMENT(logger_write(LOG_DEBUG2, "Entering foo function, x=%d", x);)

The semicolon inside the parentheses looks a bit funny, but the idea is
that the argument to COMMENT is an arbitrary line of code, not an
expression. You can probably get away with:

COMMENT(logger_write(LOG_DEBUG2, "Entering foo function, x=%d", x));

but that gives you an extra bare semicolon, which is ok in some contexts
but not in others.

Or you can make logger_write (and anything similar) a macro whose
definition depends on DEBUGMODE (and consider calling it LOGGER_WRITE).
Note that variadic macros are a new feature in C99; you might need to
use something like:

LOGGER_WRITE((LOG_DEBUG2, "Entering foo function, x=%d", x));

so it takes exactly one argument.
 
S

Shao Miller

Exactly right, Keith, except that your
#define COMMENT //
could never work because the // would be interpreted as a comment on the
macro line and get deleted, i.e. the line would be equivalent to
#define COMMENT

I assume this is the reason for the futzing around with stringifying
two / characters in the macro from my original post.

Your suggested functionlike macro may be the best available, but it's a
shame there's not a more elegant solution.

"So you want something like...except that it actually works...I don't
think you can..."
"except that your...could never work because..."

It's nice to see agreement. :)
 
J

Jens

I am porting a codebase that makes extensive use of the following
construction:

#define CAT(a,b) a##b
#define COMMENT CAT(/,/)
COMMENT This is a comment

It works as intended on the original Windows system, ...

As others have already mentioned this can't work with a complying
compiler.

But it is also not so productive, I think. This hides your code until
the day you have to debug something so there are big chances that your
code that you commented out didn't evolve in parallel with your other
code. So generally it wouldn't compile anymore.

A better solution is to put the debug code in something like

#ifndef DEBUG_ME
# define DEBUG_ME 0
#endif

if (DEBUG_ME) {
// your code comes here
}

There, the debug code is checked at every compile but any decent
compiler nowadays should completely ignore it afterwards. Then, the
day you want to use this code you can compile with -DDEBUG_ME=1 and
the code is executed.
 
L

luser- -droog

I am porting a codebase that makes extensive use of the following
construction:

#define CAT(a,b) a##b
#define COMMENT CAT(/,/)
COMMENT This is a comment

It works as intended on the original Windows system, but not on the
target compiler, which claims that comments should not be processed after
macro expansion. So I have an odd situation where the preprocessor output
is as intended and is compilable, whereas the original file is not.

What is the truth, according to the standards? If it is invalid, can
anyone suggest an alternative definition for the COMMENT macro that will
achieve the same effect?

Thanks.

What about doing an extra pre-process step?
% cc -E source_with_COMMENT.c > source_without_COMMENT.c
% cc source_without_COMMENT.c
 
L

luser- -droog

A better solution is to put the debug code in something like

#ifndef DEBUG_ME
# define DEBUG_ME 0
#endif

if (DEBUG_ME) {
 // your code comes here

}

There, the debug code is checked at every compile but any decent
compiler nowadays should completely ignore it afterwards. Then, the
day you want to use this code you can compile with -DDEBUG_ME=1 and
the code is executed.

It's also straightforward to change from a compile-time option to a
run-time option by changing DEBUG_ME to a variable. You lose the
optimize-away-when-not-in-use feature, but it greatly increases your
flexibility. Maybe you don't need the debugging output during
initialization, but you need a trace from the main loop....
 

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,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top