Preprocessing directive in the middle of macro arguments

Discussion in 'C Programming' started by Francois Grieu, Jan 16, 2008.

  1. 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
     
    Francois Grieu, Jan 16, 2008
    #1
    1. Advertising

  2. Francois Grieu <> writes:

    > 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.

    --
    Ben.
     
    Ben Bacarisse, Jan 16, 2008
    #2
    1. Advertising

  3. Francois Grieu

    John Bode Guest

    On Jan 16, 8:57 am, Francois Grieu <> 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);}
    >
    > 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.
     
    John Bode, Jan 16, 2008
    #3
  4. Francois Grieu

    Ark Khasin Guest

    John Bode wrote:
    > On Jan 16, 8:57 am, Francois Grieu <> 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);}
    >>
    >> 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.

    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>
    --
    Ark
     
    Ark Khasin, Jan 17, 2008
    #4
  5. Ark Khasin <> writes:

    > John Bode wrote:
    >> On Jan 16, 8:57 am, Francois Grieu <> 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);}
    >>>
    >>> 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?

    >>
    >> 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.


    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]

    --
    Ben.
     
    Ben Bacarisse, Jan 17, 2008
    #5
  6. Francois Grieu

    Ark Khasin Guest

    Ben Bacarisse wrote:
    > Ark Khasin <> writes:
    >
    >> John Bode wrote:
    >>> On Jan 16, 8:57 am, Francois Grieu <> 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);}
    >>>>
    >>>> 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?
    >>> 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.

    >
    > 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

    --
    Ark
     
    Ark Khasin, Jan 18, 2008
    #6
  7. Ark Khasin <> writes:

    > Ben Bacarisse wrote:
    >> Ark Khasin <> writes:
    >>
    >>> John Bode wrote:
    >>>> On Jan 16, 8:57 am, Francois Grieu <> 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);}

    <sip>
    >>> 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.

    --
    Ben.
     
    Ben Bacarisse, Jan 18, 2008
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Alex Vinokur
    Replies:
    4
    Views:
    974
    Vijay B
    Jun 26, 2003
  2. Henrik Goldman

    Recursing macro preprocessing?

    Henrik Goldman, Oct 21, 2006, in forum: C++
    Replies:
    4
    Views:
    389
    Kaz Kylheku
    Oct 22, 2006
  3. alien
    Replies:
    38
    Views:
    11,082
  4. dhun

    Macro preprocessing

    dhun, Nov 7, 2009, in forum: C Programming
    Replies:
    1
    Views:
    359
    Andrey Vul
    Nov 7, 2009
  5. entik

    macro preprocessing C51 x armcc

    entik, Mar 23, 2012, in forum: C Programming
    Replies:
    1
    Views:
    402
    entik
    Mar 23, 2012
Loading...

Share This Page