简体   繁体   中英

Conditional Preprocessor macro expansion in C

I have a macro, SOME_MACRO . It takes an argument.

Definition of SOME_MACRO :

#define SOME_MACRO(arg) __SOME_MACRO(arg)

Further I want __SOME_MACRO(arg) to expand to "ABC" if arg is 0 . And if arg is not zero, __SOME_MACRO(arg) should expand to "DEF"

Suppose I call with argument 0, that is: SOME_MACRO(0) I need to test at preprocessing time, whether the argument is zero or not.

#if <argument is zero>     // line 1
#define __SOME_MACRO(arg) "ABC"
#elif
#define __SOME_MACRO(arg) "DEF"
#endif

My question is: What should be at line 1?

Taking an example:

SOME_MACRO(2) should expand to "DEF"

SOME_MACRO(0) should expand to "ABC"

This is not possible. The expression given to #if is only evaluated once, at the line where #if is encountered. There is no way to have it evaluated again each time you invoke your macro.

As Eric Postpischil says, C does not have any general way to make the expansion of a macro conditional on its arguments.

A couple of possible alternatives:

  • Use an expression with the ternary ?: operator, as pmg suggested in a comment:

     #define __SOME_MACRO(arg) ((arg)? "DEF": "ABC")

    Then SOME_MACRO(0) will expand to ((0)? "DEF": "ABC") . Any reasonable compiler will notice that the condition is a constant, and compile this just as if you had only written "ABC" ; it should not generate code for a test nor for the unreachable branch. Conditionals with the ternary operator can even be used in expressions that must be compile-time constants, as long as the condition is itself a compile-time constant; eg __SOME_MACRO(0) can be used to initialize a global or static variable.

    Of course this will not work if the desired expansion is not syntactically an expression, eg if you are trying to use your macro to create declarations or definitions or something more syntactically elaborate.

  • If you know that only a small set of possible arguments will be used, you could use token pasting with the ## operator to expand the macro as one of another set of macros:

     #define __SOME_MACRO_0 "ABC" #define __SOME_MACRO_1 "DEF" #define __SOME_MACRO_2 "DEF" #define __SOME_MACRO(arg) __SOME_MACRO_ ## arg

    Then __SOME_MACRO(0) expands to "ABC" and __SOME_MACRO(2) expands to "DEF" . However __SOME_MACRO(3) will not compile unless you write a corresponding __SOME_MACRO_3 macro, and __SOME_MACRO(0+1) cannot be made to work at all, at least not in any way that I know of.

    (As written, __SOME_MACRO(0+1) expands to "ABC"+1 , which is equivalent to "BC" and will probably cause you a lot of confusion before you figure out what is wrong. __SOME_MACRO(1-1) is even worse...)

    Also, #define ZERO 0 followed by __SOME_MACRO(ZERO) doesn't work as it stands, thought it can be fixed by doing

    #define SECOND_MACRO(arg) __SOME_MACRO_ # arg #define __SOME_MACRO(arg) SECOND_MACRO(arg)

Here is a solution for the requested behavior. Do not use it, it is bad practice, and you should not be attempting this.

/*  Define __SOME_MACRO:

        Defer is used so that its arguments will be macro-replaced before
        Kludge is processed.

        "Kludge" is pasted to arg.  If this makes "Kludge0", it will be
        replaced by two arguments (an empty argument, a comma, and the argument
        "abc").  Otherwise, if it forms a single token, that is one argument.
        (If the pasting does not form a proper token, the behavior is
        undefined.  Most likely, the compiler will report an error.)

        The resulting argument(s) are then passed to Kludge, followed by "DEF".

        Kludge is replaced by its second argument.  If __SOME_MACRO's argument
        was "0", this second argument is "ABC".  Otherwise, it is "DEF".
*/
#define Kludge0             , "ABC"
#define Kludge(x, y,...)    y
#define Defer(x, ...)       Kludge(x, __VA_ARGS__)
#define __SOME_MACRO(arg)   Defer(Kludge##arg, "DEF",)

__SOME_MACRO(0)
__SOME_MACRO(2)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM