Home > front end >  What is the order of the C preprocessor macro expansion?
What is the order of the C preprocessor macro expansion?

Time:08-02

English is not my native language; thus I show the code to depict.

#define concat_temp(x, y) x##y
#define concat(x, y) concat_temp(x, y)
#define CHOOSE2nd(a, b, ...) b
#define MUX_WITH_COMMA(contain_comma, a, b) CHOOSE2nd(contain_comma a, b)
#define MUX_MACRO_PROPERTY(p, macro, a, b) MUX_WITH_COMMA(concat(p, macro), a, b)
#define __P_DEF_0 X,
#define __P_DEF_1 X,
#define MUXDEF(macro, X, Y) MUX_MACRO_PROPERTY(__P_DEF_, macro, X, Y)
#define ISDEF(macro) MUXDEF(macro, 1, 0)

#define FOO 1

int main(int argc, char* argv[]) {
    ISDEF(FOO) // 1
    MUXDEF(FOO, 1, 0) // 1
    MUX_MACRO_PROPERTY(__P_DEF_, FOO, 1, 0) // 1
    MUX_WITH_COMMA(concat(__P_DEF_, FOO), 1, 0) // 1

    CHOOSE2nd(concat(__P_DEF_, FOO) 1, 0) // 0 !!! why?
    
    concat(__P_DEF_, FOO) // X,

    CHOOSE2nd(X, 1, 0) // 1


    return 0;
}

I am trying to expand the macro ISDEF manually, but I ran into some trouble.

When the macro is defined as 0 or 1, the ISDEF will be expanded to 1. However, there are more args that need to be expanded in MUX_WITH_COMMA(concat(__P_DEF_, FOO), 1, 0) which are MUX_WITH_COMMA and concat; I think the former will be expanded first in that MUX_WITH_COMMA(X,, 1, 0) is incorrect.

In the line which I expand manually CHOOSE2nd(concat(__P_DEF_, FOO) 1, 0) the first expansion is CHOOSE2nd and the result is 0; but in the original expression the order should be

  1. MUX_WITH_COMMA -> CHOOSE2nd
  2. concat(__P_DEF_, FOO) -> X,
  3. CHOOSE2nd(X, 1, 0) -> 1

I guess that the preprocessor will expand the args in the brackets after processing the other part just once, and then repeat this process until no macro can be expanded. Is it the right explanation?

Another likely possible order is that the preprocessor will prioritize the args in bracket, like this:

    ISDEF(1) // 1
    MUXDEF(1, 1, 0) // 1
    MUX_MACRO_PROPERTY(__P_DEF_, 1, 1, 0) // 1
    MUX_WITH_COMMA(concat(__P_DEF_, 1), 1, 0) // 1
    CHOOSE2nd(concat(__P_DEF_, 1) 1, 0) // 0
    CHOOSE2nd(X, 1, 0) // 1

CodePudding user response:

Although I have still not found a reliable reference to explain it, it seems that the expanded arg which contains comma will not be counted as two args. Like this:

#define FOO(x) x
#define A a,a

int main() {
    FOO(A) // a,a
}

Thus the correct order in the question is that:

ISDEF(1) // 1
    MUXDEF(1, 1, 0) // 1
    MUX_MACRO_PROPERTY(__P_DEF_, 1, 1, 0) // 1
    MUX_WITH_COMMA(concat(__P_DEF_, 1), 1, 0) // 1
    //MUX_WITH_COMMA(X,, 1, 0) // compile error
    //But if the `X,` is expand by a macro it will not be count as two args.
    CHOOSE2nd(X, 1, 0) // 1

CodePudding user response:

  • Expand ISDEF(FOO)

    • Expand FOO

      -> 1

    -> MUXDEF(1, 1, 0)

  • Expand MUXDEF(macro, X, Y)

    -> MUX_MACRO_PROPERTY(__P_DEF_, 1, 1, 0)

  • Expand MUX_MACRO_PROPERTY(p, macro, a, b)

    -> MUX_WITH_COMMA(concat(__P_DEF_, 1), 1, 0)

    • Expand concat(x, y)

      -> concat_temp(__P_DEF_, 1)

    • Expand concat_temp(__P_DEF_, 1)

      -> __P_DEF_##1

    • Apply ##

      -> __P_DEF_1

    • Expand __P_DEF_1

      -> X,

    -> MUX_WITH_COMMA(X, 1, 0)

  • Expand MUX_WITH_COMMA(contain_comma, a, b)

    -> CHOOSE2nd(X, 1, 0)

  • Expand CHOOSE2nd(a, b, ...)

    -> 1


  • Expand ISDEF(BAR)

    -> MUXDEF(BAR, 1, 0)

  • Expand MUXDEF(macro, X, Y)

    -> MUX_MACRO_PROPERTY(__P_DEF_, BAR, 1, 0)

  • Expand MUX_MACRO_PROPERTY(p, macro, a, b)

    -> MUX_WITH_COMMA(concat(__P_DEF_, BAR), 1, 0)

    • Expand concat(x, y)

      -> concat_temp(__P_DEF_, BAR)

    • Expand concat_temp(__P_DEF_, BAR)

      -> __P_DEF_##BAR

    • Apply ##

      -> __P_DEF_BAR

    -> MUX_WITH_COMMA(__P_DEF_BAR, 1, 0)

  • Expand MUX_WITH_COMMA(contain_comma, a, b)

    -> CHOOSE2nd(__P_DEF_BAR 1, 0)

  • Expand CHOOSE2nd(a, b, ...)

    -> 0

  • Related