Difference between Microsoft Visual Studio preprocessor and gcc's

Answered Difference between Microsoft Visual Studio preprocessor and gcc's

  • viernes, 13 de julio de 2012 14:28
     
      Tiene código

    I discovered that Microsoft Visual Studio preprocessor and gcc's preprocessor treat the following sample differently:

    # define M3(x, y, z) x + y + z
    # define M2(x, y) M3(x, y)
    # define P(x, y) {x, y}
    # define M(x, y) M2(x, P(x, y))
    M(a, b)
    

    'cl /E' produces the following:

    a + {a, b} +

    , while output from 'gcc -E' looks like this:

    a + {a + b}
    It seems that MS preprocessor doesn't consider commas that came from nested macro expansions to be argument separators. I suppose this is not compliant with C/C++ standards. Is this an extension to the standard? If yes, what is the point of this extension and where is it described?

Todas las respuestas

  • viernes, 13 de julio de 2012 15:07
     
     

    SSyr wrote:

    I discovered that Microsoft Visual Studio preprocessor and gcc's preprocessor treat the following sample differently:

    # define M3(x, y, z) x + y + z
    # define M2(x, y) M3(x, y)
    # define P(x, y) {x, y}
    # define M(x, y) M2(x, P(x, y))
    M(a, b)
    
    /E' produces the following:
    a + {a, b} +

    , while output from 'gcc -E' looks like this:

    a + {a + b}

    GCC is right, MSVC is wrong.

    It seems that MS preprocessor doesn't consider commas that came from  nested macro expansions to be argument separators. I suppose
    this is not compliant with C/C++ standards. Is this an extension to  the standard?

    As far as I can tell, this is plain old bug.


    Igor Tandetnik

  • viernes, 13 de julio de 2012 16:38
     
     Respondida Tiene código

    You're using the incorrect number of arguments to M3.

    Your M2 macro contains an invocation of the M3 macro with the incorrect number of arguments.  If you want the M3 macro to be expanded with 3 arguments then then you'll need to pass through the argument y to a macro that expands it.

    V is for verbatim in my line of thinking here.

    #define V(...) __VA_ARGS__
    #define M2(x,y) V(M3(x,y))
    

    The essence of my V macro is just a pass through.  I could also have done this:

    #define V(x) x

    ... except that the variadic version keeps the argument list intact -- pointless in this example.  This doesn't really change what's going on.

    The standard says (10.16.4) that there shall be more arguments in the invocation than there are parameters in the macro definition.

    If the identifier-list in the macro definition does not end with an ellipsis, the number of arguments (including
    those arguments consisting of no preprocessing tokens) in an invocation of a function-like macro shall equal
    the number of parameters in the macro definition. Otherwise, there shall be more arguments in the invocation
    than there are parameters in the macro definition (excluding the ...). There shall exist a ) preprocessing
    token that terminates the invocation.

    Having said that, the documentation for warning C4003 (not enough actual parameters for macro 'identifier') claims that missing parameters are substituted with empty text.  That explains the "bug" behaviour you saw.

    I guess what's key here is the interpretation of what constitutes an invocation.  The macro BEFORE EXPANSION must have the correct number of arguments in its invocation.  Note that when the text of "M3(x,y)" is passed through as an argument it is not an invocation.  The expansion of y happens first, then the invocation of M3 happens after y has expanded and results in tokens that produce the correct number of arguments to M3.

    Is this the correct interpretation?  I dunno.  Obviously cl and gcc are different here.  But I think there's some standards interpretation to be clarified before you can call it a bug.  I can easily see how you could interpret the original definition as not being an invocation and just being text replacement.  But there are rules about the tokens for text replacement, so this isn't simple as just passing through text.  Can of worms opened here, I think.  It would be nice if the standard referred directly to this scenario.

  • viernes, 13 de julio de 2012 17:36
     
      Tiene código

    According to the standard, the expansion of macro 'M' begins with the following steps:

    1) Arguments substitution:

    M(a, b)

    2) Macro substitution:

    M2(a, P(a, b))

    3) Expansion of the resulting token sequence. Its first step is also argument substitution:

    M2(a, {a, b})

    Now, according to the standard, we have a correct macro call with 3 arguments. But MS cl for some reasons considers "{a, b}" to be a single argument (?). Don't pay attention to "{}" - they can be omitted or replaced with other symbols. I'm wondering if somebody knows those reasons and is able to explain how MS preprocessor works.

  • viernes, 13 de julio de 2012 17:37
     
     
    Thanks. Is this old bug described anywhere?
  • viernes, 13 de julio de 2012 17:54
     
     Respondida

    SSyr wrote:

    Thanks. Is this old bug described anywhere?

    I used "old" as a figure of speech, like "good old times", not literally  to mean that the bug is known. Having said that, a metric boatload of  preprocessor-related bugs has been filed:

    https://connect.microsoft.com/VisualStudio/SearchResults.aspx?SearchQuery =preprocessor

    I'm too lazy to dig through them to see if yours is among them. You can  of course go ahead and file a new one.


    Igor Tandetnik

  • viernes, 13 de julio de 2012 18:24
     
     

    >It seems that MS preprocessor doesn't consider commas that came from nested macro expansions to be argument separators.

    As Igor mentions, submit this as a bug report on the MS connect site -
    at least then we're sure MS are aware of the issue.

    Dave

  • lunes, 16 de julio de 2012 19:09
     
     

    And you can peruse the boost mailing list archives to see Paul Mensonides' discussion of the fundamental errors in MSVC preprocessor.

    Jeff