【问题标题】:Is it possible to a Macro evaluate multiple arguments to another?宏是否可以将多个参数评估给另一个?
【发布时间】:2012-04-19 18:10:28
【问题描述】:

我想做这样的事情:

#define NEED3ARGS(a1,a2,a3) ( "[" #a1 " + " #a2 " + " #a3 "]" )
#define MULTIARG()  ARG1, ARG2, ARG3

NEED3ARGS( MULTIARG() )

我希望它输出如下内容:

( "[" "ARG1" " + " "ARG2" " + " "ARG3" "]" )

但我有:

$ cpp multiarg.c 
# 1 "multiarg.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "multiarg.c"

multiarg.c:4:23: error: macro "NEED3ARGS" requires 3 arguments, but only 1 given
NEED3ARGS

有没有办法使用 ANSI-C/GNU GCC 和 C 预处理器来做我想做的事?

谢谢!

【问题讨论】:

    标签: c c-preprocessor


    【解决方案1】:

    你需要一些间接性。使用 C99:

    #define NEED3ARGS(a1,a2,a3) ( "[" #a1 " + " #a2 " + " #a3 "]" )
    #define INVOKE_NEED3ARGS(...) NEED3ARGS(__VA_ARGS__)
    #define MULTIARG()  ARG1, ARG2, ARG3
    
    INVOKE_NEED3ARGS( MULTIARG() )
    

    (C99 不是严格要求;您可以将可变参数宏替换为固定数量的宏。)

    如果您需要使用 Visual C++ 编译源代码,则需要更多的间接性(因为 a compiler bug):

    #define NEED3ARGS(a1,a2,a3) ( "[" #a1 " + " #a2 " + " #a3 "]" )
    #define INVOKE_NEED3ARGS_(...) NEED3ARGS __VA_ARGS__
    #define INVOKE_NEED3ARGS(...) INVOKE_NEED3ARGS_((__VA_ARGS__))
    #define MULTIARG()  ARG1, ARG2, ARG3
    
    INVOKE_NEED3ARGS( MULTIARG() )
    

    至于为什么需要间接:宏参数在被替换到替换列表之前不会被评估和宏替换。因此,当您尝试 NEED3ARGS(MULTIARG()) 时,MULTIARG() 直到宏调用开始之后才会被评估,因此它被视为单个参数。

    INVOKE_NEED3ARGS 宏确保在调用 NEED3ARGS 之前对其参数进行完全评估。 __VA_ARGS__ 被替换为INVOKE_NEED3ARGS 的宏替换参数,即ARG1, ARG2, ARG3,然后使用这些参数调用NEED3ARGS

    【讨论】:

      【解决方案2】:

      是的,

      #define NEED3ARGS(a1,a2,a3) ( "[" #a1 " + " #a2 " + " #a3 "]" )
      #define MULTIARG()  ARG1, ARG2, ARG3
      #define NEED1ARG(ARG) NEED3ARGS(ARG)
      
      NEED1ARG( MULTIARG() )
      

      您需要将它包装在另一个宏调用中,以便在调用 NEED3ARGS 之前扩展参数。

      【讨论】:

        【解决方案3】:

        除了 James McNellis 的回答之外,如果您需要将此技巧应用于许多类似函数的宏 (flm),您可以定义一个“调用”宏来为您完成该技巧。这是一个完整的工作示例:

        #include<cstdio>
        int f(int x,int y) { return x + y; }
        #define g(x,y) x+y
        #define XY  1,2
        #define _g(arg) g(arg)
        #define invoke(flm,...) flm(__VA_ARGS__)
        int main(int argc, char ** argv)
        {
          printf("%d\n",f(XY));        // functions are easy
          printf("%d\n",_g(XY));       // Jam,es' way
          printf("%d\n",invoke(g,XY)); // with generic invoke flm
          return 0;
        }
        

        【讨论】:

          猜你喜欢
          • 2019-12-17
          • 2011-07-12
          • 1970-01-01
          • 1970-01-01
          • 2019-01-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多