Preprocessing directive in the middle of macro arguments

F

Francois Grieu

One of the C compiler that I use <OT>(Keil's CX51)</OT> barks at

#define a(b) b
int main(void){return a(
#if 0
#endif
0);}

More generally, this compiler seems confused by any preprocessing
directive in the middle of macro arguments, which comes handy e.g. to
conditionaly select one of several arguments passed to a macro.

Is it a compiler bug? Where does C89 define if this is valid or not?

TIA.
Francois Grieu
 
B

Ben Bacarisse

Francois Grieu said:
One of the C compiler that I use <OT>(Keil's CX51)</OT> barks at

#define a(b) b
int main(void){return a(
#if 0
#endif
0);}

More generally, this compiler seems confused by any preprocessing
directive in the middle of macro arguments, which comes handy e.g. to
conditionaly select one of several arguments passed to a macro.

Is it a compiler bug? Where does C89 define if this is valid or not?

No, I think it is not permitted. In C89:

3.8.3 Macro replacement
...
If there are sequences of preprocessing tokens within the list of
arguments that would otherwise act as preprocessing directives, the
behavior is undefined.

The same wording appears in C99 but it is in section 6.10.3.
 
J

John Bode

One of the C compiler that I use <OT>(Keil's CX51)</OT> barks at

#define a(b) b
int main(void){return a(
#if 0
#endif
0);}

More generally, this compiler seems confused by any preprocessing
directive in the middle of macro arguments, which comes handy e.g. to
conditionaly select one of several arguments passed to a macro.

Is it a compiler bug? Where does C89 define if this is valid or not?

TIA.
  Francois Grieu

It's not a bug; you cannot embed preprocessor commands in a macro.
All preprocessor directives are processed before any macro expansion
takes place, so any preprocessor directives embedded in a macro will
not be recognized as such, but will instead be translated as regular C
code.
 
A

Ark Khasin

John said:
It's not a bug; you cannot embed preprocessor commands in a macro.
All preprocessor directives are processed before any macro expansion
takes place, so any preprocessor directives embedded in a macro will
not be recognized as such, but will instead be translated as regular C
code.
The OP's code has no embedded directives; it's equivalent to
#define a(b) b
int main(void){return a(
0);}
Which is good C, IMHO. So I think it's a compiler bug.
<OT>
Getting the C front end right is surprisingly hard; there are enough C
vendors to make a market for C front end parsers, and it exists.
Still, some people do it on their own, and sometimes incorrectly. I had
trouble with Keil for ARM (see
http://www.macroexpressions.com/dl/compileme.c), but I never tried their
latest version.
I wonder if this fixes the OP problem :)
#de\
fine \
a(b\
b)=bb
</OT>
 
B

Ben Bacarisse

Ark Khasin said:
The OP's code has no embedded directives; it's equivalent to
#define a(b) b
int main(void){return a(
0);}
Which is good C, IMHO. So I think it's a compiler bug.

I disagree. Are you saying that the OP's code is equivalent to the
above because of John Bode's: "All preprocessor directives are
processed before any macro expansion takes place"? If so, I think you
have been misled. In section 5.1.1.2 ("Translation phases") is says:

4. Preprocessing directives are executed, macro invocations are
expanded, and _Pragma unary operator expressions are executed. If a
character sequence that matches the syntax of a universal character
name is produced by token concatenation (6.10.3.3), the behavior is
undefined. A #include preprocessing directive causes the named
header or source file to be processed from phase 1 through phase 4,
recursively. All preprocessing directives are then deleted.

so all pre-processing happens "at once". I may have missed something
that does give the OP's code a portable meaning, but I need
persuading. Until then I stand by my previous quote that:

If there are sequences of preprocessing tokens within the list of
arguments that would otherwise act as preprocessing directives,
the behavior is undefined. [6.10.3]
 
A

Ark Khasin

Ben said:
Ark Khasin said:
The OP's code has no embedded directives; it's equivalent to
#define a(b) b
int main(void){return a(
0);}
Which is good C, IMHO. So I think it's a compiler bug.

I disagree. Are you saying that the OP's code is equivalent to the
above because of John Bode's: "All preprocessor directives are
processed before any macro expansion takes place"? If so, I think you
have been misled. In section 5.1.1.2 ("Translation phases") is says:

4. Preprocessing directives are executed, macro invocations are
expanded, and _Pragma unary operator expressions are executed. If a
character sequence that matches the syntax of a universal character
name is produced by token concatenation (6.10.3.3), the behavior is
undefined. A #include preprocessing directive causes the named
header or source file to be processed from phase 1 through phase 4,
recursively. All preprocessing directives are then deleted.

so all pre-processing happens "at once". I may have missed something
that does give the OP's code a portable meaning, but I need
persuading. Until then I stand by my previous quote that:

If there are sequences of preprocessing tokens within the list of
arguments that would otherwise act as preprocessing directives,
the behavior is undefined. [6.10.3]

I read the OP's code as follows:
1. definition of a(b) is read
2. macro invocation "a(" is found; need to build replacement list
3. the #if directive is found; need to evaluate
4. expression evaluates to 0, need to skip to #endif
5. skipped to #endif; continue building replacement list
6. found a replacement parameter and a right paren; r.l. built.
7. perform the macro expansion
8. etc.

I see /your/ reading of the code. If it were correct, we'd have an
ambiguity. However, 6.10.3 resolves it:
8 If a # preprocessing token, followed by an identifier, occurs
lexically at the point at which a preprocessing directive could begin,
the identifier is not subject to macro replacement.
That is, #if is not replaced which turns it into a directive - which
goes on to skip to #endif
 
B

Ben Bacarisse

Ark Khasin said:
Ben said:
Ark Khasin said:
John Bode wrote:
One of the C compiler that I use <OT>(Keil's CX51)</OT> barks at

#define a(b) b
int main(void){return a(
#if 0
#endif
0);}
The OP's code has no embedded directives; it's equivalent to
#define a(b) b
int main(void){return a(
0);}
Which is good C, IMHO. So I think it's a compiler bug.

I disagree. Are you saying that the OP's code is equivalent to the
above because of John Bode's: "All preprocessor directives are
processed before any macro expansion takes place"? If so, I think you
have been misled. In section 5.1.1.2 ("Translation phases") is says:

4. Preprocessing directives are executed, macro invocations are
expanded, and _Pragma unary operator expressions are executed. If a
character sequence that matches the syntax of a universal character
name is produced by token concatenation (6.10.3.3), the behavior is
undefined. A #include preprocessing directive causes the named
header or source file to be processed from phase 1 through phase 4,
recursively. All preprocessing directives are then deleted.

so all pre-processing happens "at once". I may have missed something
that does give the OP's code a portable meaning, but I need
persuading. Until then I stand by my previous quote that:

If there are sequences of preprocessing tokens within the list of
arguments that would otherwise act as preprocessing directives,
the behavior is undefined. [6.10.3]

I read the OP's code as follows:
1. definition of a(b) is read
2. macro invocation "a(" is found; need to build replacement list
3. the #if directive is found; need to evaluate

I think paragraph 11 of 6.10.3 applies here. Do you not think so?
4. expression evaluates to 0, need to skip to #endif
5. skipped to #endif; continue building replacement list
6. found a replacement parameter and a right paren; r.l. built.
7. perform the macro expansion
8. etc.

I see /your/ reading of the code. If it were correct, we'd have an
ambiguity. However, 6.10.3 resolves it:
8 If a # preprocessing token, followed by an identifier, occurs
lexically at the point at which a preprocessing directive could begin,
the identifier is not subject to macro replacement.
That is, #if is not replaced which turns it into a directive - which
goes on to skip to #endif

Paragraph 8 just says that the names of directives aren't expanded. I
think paragraph 11 is the key bit. You outline a very clear sequence
of actions but the wording of the standard does no support things
happening in that exact order and in that exact way.
 

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
473,754
Messages
2,569,527
Members
45,000
Latest member
MurrayKeync

Latest Threads

Top