我试图使用可变长度宏创建和初始化结构。我希望能够使用'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>
有没有办法实现这个目标?
答案 0 :(得分:1)
可以通过参数计数和连接的组合来完成。
首先,您需要一个计算其参数的宏,我将其称为NARGS
这已被问及并回答here。请注意,答案取决于编译器。
接下来,您需要针对所有特定情况的一系列宏:
#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}
您还需要一个串联宏:
#define CONCAT(a, b) a##b
最后,使用连接选择正确的连接:
#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
的调用中的最后一个逗号会导致相同的可移植性问题