在 x-macro 定义中使用宏作为参数

Using a macro as an argument in an x-macro definition

考虑以下用户风格 x-macro:

#define PRIMES_X(func) \
  func(2) \
  func(3) \
  func(5)

我们可以使用它来调用传入的宏 func 重复前三个质数。例如:

#define MAKE_FUNC(num) void foo ## num();
PRIMES_X(MAKE_FUNC)

将声明返回 void 的函数 foo2()foo3()foo5().

到目前为止,还不错。现在假设我想在 x-macro 本身的定义中使用一个宏作为参数,如下所示:

#define MAX_PRIME 5
#define PRIMES_X(func) \
  func(2) \
  func(3) \
  func(MAX_PRIME)

它不起作用,因为 MAKE_FUNC 现在将尝试声明 void fooMAX_PRIME(),因为(我想)标记连接发生时没有扩展 MAX_PRIME

我可以解决这个问题,让它像以前一样声明 foo5() 吗?

您可以插入另一层宏展开(下图PRIMES_X2)。

#define MAKE_FUNC(num) void foo ## num();
#define MAX_PRIME 5
#define PRIMES_X(func) PRIMES_X2(func, MAX_PRIME)
#define PRIMES_X2(func, maxPrimePar) \
  func(2) \
  func(3) \
  func(maxPrimePar)

PRIMES_X(MAKE_FUNC)

输出 gcc -E:

void foo2(); void foo3(); void foo5();

Yunnosch 的回答很好,但要进一步旋转 X 宏的疯狂程度,您还可以在列表内调用宏而不是在列表外调用包装器宏。这样做的好处是您可以将 "variables" 从列表传递给被调用的宏。

我想这可能会有一些用处 - 例如,假设您希望使用 X 宏来声明不同类型的函数?

示例:

#define MAX_PRIME 5

#define CREATE_FUNC(func, ret_type, param) func(ret_type, param)

#define PRIMES_X(func)                 \
  CREATE_FUNC(func, int,    2)         \
  CREATE_FUNC(func, void,   3)         \
  CREATE_FUNC(func, double, MAX_PRIME) \

#define MAKE_FUNC(ret_type, num) ret_type foo ## num(void);
  PRIMES_X(MAKE_FUNC)
#undef MAKE_FUNC

调试代码以检查函数是否确实获得了预期的原型:

int main(void)
{
  (void)foo2();
  foo3();
  (void)foo5();
}

int foo2 (void){ return 0;}
void foo3 (void){}
double foo5 (void){ return 0.0;}