在C中创建和初始化具有可变长度宏的结构

时间:2017-08-18 21:03:40

标签: c macros

我试图使用可变长度宏创建和初始化结构。我希望能够使用'0'创建/初始化结构,然后使用可选传入的值初始化结构的某些字段。

这可能吗?我正在尝试以下方法:

#define INIT_ENTRY(x, ...) \
    entry_t x = {.id = 0, .age = 0} \
    x.id  = <I want to use arg1 here>
    x.age = <i want to use arg2 here if it exists> 

有没有办法实现这个目标?

2 个答案:

答案 0 :(得分:1)

可以通过参数计数和连接的组合来完成。

  1. 首先,您需要一个计算其参数的宏,我将其称为NARGS这已被问及并回答here。请注意,答案取决于编译器。

  2. 接下来,您需要针对所有特定情况的一系列宏:

    #define INIT_ENTRY_0(x) entry_t x = {.id = 0, .age = 0}
    #define INIT_ENTRY_1(x, _id) entry_t x = {.id = _id, .age = 0}
    #define INIT_ENTRY_2(x, _id, _age) entry_t x = {.id = _id, .age = _age}

  3. 您还需要一个串联宏:

    #define CONCAT(a, b) a##b

  4. 最后,使用连接选择正确的连接:

    #define INIT_ENTRY(x, ...) CONCAT(INIT_ENTRY_, NARGS(__VA_ARGS__))(x, #__VA_ARGS__)

答案 1 :(得分:0)

如果您在宏中保留与初始化列表中相同的初始化顺序,那么如果您始终将其他所有内容初始化为0,则可以执行以下操作:

#define _INIT_ENTRY_UTILITY(x, ID_, AGE_, ...) \
   entry_t x = {.id = ID_, .age = AGE_}
#define INIT_ENTRY(...) _INIT_ENTRY_UTILITY(__VA_ARGS__, 0, 0, )

我假设你的真实用例有两个以上的参数;如果采用这种方法,请确保完全模仿其形式以保持可移植性。特别是:

  • 更改为#define INIT_ENTRY(x, ...)以获得“清晰度”会破坏标准 C预处理器上的INIT_ENTRY(foo)调用。更糟糕的是,它实际上可以在一些流行的cpp(例如gnu)上运行,它支持扩展等功能,因此隐藏了可移植性问题。
  • _INIT_ENTRY_UTILITY的替换列表中删除对INIT_ENTRY的调用中的最后一个逗号会导致相同的可移植性问题