当括号导致语法错误时,如何在宏参数内的括号内使用逗号?

ick*_*fay 14 c macros c99 c-preprocessor

我已经定义了一些宏来简化定义结构数组,但我找不到一种方法来使用它们而不会产生错误.下面是宏(以及一些示例结构,用于演示可能使用宏的原因(我填充的实际结构稍微复杂一些)):

struct string_holder {
    const char *string;
};
struct string_array_holder {
    struct string_holder *holders;
};
#define DEFINE_STRING_ARRAY_HOLDER(name, values) \
    static struct string_holder name##__array[] = values; \
    static struct string_array_holder name = { name##__array }
#define WRAP_STRING(string) { string }
Run Code Online (Sandbox Code Playgroud)

当你使用它来声明一个项目的数组时,它工作得很好:

DEFINE_STRING_ARRAY_HOLDER(my_string_array_holder, {
    WRAP_STRING("my string")
});
Run Code Online (Sandbox Code Playgroud)

但是当我使用多个项目时:

DEFINE_STRING_ARRAY_HOLDER(my_string_array_holder, {
    WRAP_STRING("hello"),
    WRAP_STRING("world")
});
Run Code Online (Sandbox Code Playgroud)

我收到此错误:

错误:为类似函数的宏调用提供了太多参数

所以它将大括号中的逗号解释为参数分隔符.我遵循这个问题的建议,并在括号中加入有问题的论点:

DEFINE_STRING_ARRAY_HOLDER(my_string_array_holder, ({
    WRAP_STRING("hello"),
    WRAP_STRING("world")
}));
Run Code Online (Sandbox Code Playgroud)

现在,当我尝试编译它时,它将其解释({ ... })语句表达式并抱怨:

警告:使用GNU语句表达式扩展
(由于其解释为语句表达式而产生的一堆语法错误)
错误:文件范围内不允许使用语句表达式

我怎么能:

  • 使用宏没有错误(首选),或
  • 重写宏[s]在这些情况下工作?

kay*_*kay 14

Dmitri是对的,变量宏可行的方法.

我把一些示例代码用于测试给定键是否是值列表的成员:

#define _IN(KEY, ...)                                             \
({                                                                \
  typedef __typeof(KEY) _t;                                       \
  const _t _key = (KEY);                                          \
  const _t _values[] = { __VA_ARGS__ };                           \
  _Bool _r = 0;                                                   \
  unsigned int _i;                                                \
  for (_i = 0; _i < sizeof(_values) / sizeof(_values[0]); ++_i) { \
    if (_key == _values[_i]) {                                    \
      _r = 1;                                                     \
      break;                                                      \
    }                                                             \
  }                                                               \
  _r;                                                             \
})
Run Code Online (Sandbox Code Playgroud)

注意使用__VA_ARGS__.

更新: 如果你不喜欢__VA_ARGS__在任意位置的粗略解决方案将是一个"unwrapper"宏:

#define UNWRAP(...) __VA_ARGS__
Run Code Online (Sandbox Code Playgroud)

您可以像前缀运算符一样使用它.;-)

#include <stdio.h>

/* "unwrapper": */
#define UNWRAP(...) __VA_ARGS__

/* your macros: */
#define WRAP(NAME, ELEMS) static const char *NAME[] = { UNWRAP ELEMS }

int main(void) {
  WRAP(some_test, ("a", "b", "c"));
  printf("The second elem in some_test is: '%s'\n", some_test[1]);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 实际上,那个"UNWRAP"的东西很整洁.谢谢! (3认同)