我想在编译时使用宏定义数据结构。数据结构看起来像:
struct {
int a;
int b;
int c;
unsigned int top;
unsigned int first;
} array[N];
其中 N 是某个编译时间常数。然后用户定义一个宏,如下所示:
#define List \
(10, -3, 8, \
(-1, -1, 13, \
(0, -7, 15, Empty)), \
(-4, 14, 13, Empty)), \
(17, 0, 1, Empty), \
(3, 3, 3, \
(1, 1, 0, Empty)) \
从中生成
array
。结果将是:
array = {
[0] = {10, -3, 8, NoValue, 1/*array[1]*/},
[1] = {-1, -1, 13, 0/*array[0]*/, 2/*array[2]*/},
[2] = {0, 7, 15, 0/*array[0]*/, NoValue},
[3] = {-4, 14, 13, 0/*array[0]*/, NoValue},
[4] = {17, 0, 1, NoValue, NoValue},
[5] = {3, 3, 3, NoValue, 6/*array[6]*/},
[6] = {1, 1, 0, 5/*array[5]*/, NoValue},
};
哪里
#define NoValue 9000 /* special value used only for this purpose */
。基本上为 () 中包含的每个元素在 array
中创建条目。另外,将子元素链接到父元素,并将父元素链接到其第一个子元素。
到目前为止,我使用的是来自https://stackoverflow.com/a/11994395/1806687的FOR_EACH宏。问题是,定义
array
条目的宏还包含 FOR_EACH 宏,以迭代任何可能的子元素,这些子元素会崩溃并且不起作用。
我怎样才能做到这一点?
编辑:
我猜第一个障碍是递归地迭代树来为每个元素定义一个枚举()。我们可以向每个元素添加一个参数,如下所示
#define List (Name1, 10, -3, 8, ...
,从中我们可以生成一个枚举,然后我们可以使用其值来代替数组索引(顶部和第一个成员)。
#define List \
(Name1, 10, -3, 8, \
(Name2, -1, -1, 13, \
(Name3, 0, -7, 15, Empty)), \
(Name4, -4, 14, 13, Empty)), \
(Name5, 17, 0, 1, Empty), \
(Name6, 3, 3, 3, \
(Name7, 1, 1, 0, Empty)) \
#define EnumFromList(name, a, b, c, top, first) \
enum_##name,
enum NameEnum {
FOR_EACH(EnumFromList, List)
};
不过,子元素的嵌套阻碍了对此问题的简单解决方案(据我所知)。
编辑2:
我使用的实际数据结构看起来更像是:
struct {
int a;
int b;
int c;
unsigned int top;
unsigned int parent;
unsigned int first;
} array[N];
其中
top
是顶部父元素的数组索引 parent
是直接(第一个)父元素的数组索引,first
是第一个子元素的数组索引。
以下代码:
#define NOVALUE ((unsigned)-1)
#define EXPAND(...) __VA_ARGS__
#define ADDONE(...) +1
// -----------------------------------
#define IF_EMPTY_IN(a, ...) a
#define IF_EMPTY(t, f, ...) IF_EMPTY_IN(__VA_OPT__(f,) t, )
// --------------------------
#define TREE_VAL(idx, a, b, c, up, down) \
[idx] = {a, b, c, up, down},
// -----------------------------------
#define TREE_L4_NEXT(...)
#define TREE_L4_VAL_IN(f, idx, up, a, b, c, ...) \
f(idx, a, b, c, up, IF_EMPTY(NOVALUE, idx+1 __VA_OPT__(,) __VA_ARGS__)) \
TREE_L4_NEXT(f, idx+1, idx __VA_OPT__(,) __VA_ARGS__)
#define TREE_L4_VAL(...) \
TREE_L4_VAL_IN(__VA_ARGS__)
#define TREE_L4_0(f, idx, up, a)
#define TREE_L4_1(f, idx, up, a) \
TREE_L4_VAL(f, idx, up, EXPAND a)
#define TREE_L4_2(f, idx, up, a, ...) \
TREE_L4_1(f, idx, up, a) \
TREE_L4_1(f, idx TREE_L1_NEXT(ADDONE,,,a), up, __VA_ARGS__)
#define TREE_L4_3(f, idx, up, a, ...) \
TREE_L4_1(f, idx, up, a) \
TREE_L4_2(f, idx TREE_L1_NEXT(ADDONE,,,a), up, __VA_ARGS__)
#define TREE_L4_N(_3,_2,_1,_0,N,...) \
TREE_L4##N
#define TREE_L4(f, idx, up, ...) \
TREE_L4_N(__VA_OPT__(,) __VA_ARGS__,_3,_2,_1,_0)(f, idx, up, __VA_ARGS__)
#define TREE_L3_NEXT(...) TREE_L4(__VA_ARGS__)
#define TREE_L3_VAL_IN(f, idx, up, a, b, c, ...) \
f(idx, a, b, c, up, IF_EMPTY(NOVALUE, idx+1 __VA_OPT__(,) __VA_ARGS__)) \
TREE_L3_NEXT(f, idx+1, idx __VA_OPT__(,) __VA_ARGS__)
#define TREE_L3_VAL(...) \
TREE_L3_VAL_IN(__VA_ARGS__)
#define TREE_L3_0(f, idx, up, a)
#define TREE_L3_1(f, idx, up, a) \
TREE_L3_VAL(f, idx, up, EXPAND a)
#define TREE_L3_2(f, idx, up, a, ...) \
TREE_L3_1(f, idx, up, a) \
TREE_L3_1(f, idx TREE_L3_NEXT(ADDONE,,,a), up, __VA_ARGS__)
#define TREE_L3_3(f, idx, up, a, ...) \
TREE_L3_1(f, idx, up, a) \
TREE_L3_2(f, idx TREE_L3_NEXT(ADDONE,,,a), up, __VA_ARGS__)
#define TREE_L3_N(_3,_2,_1,_0,N,...) \
TREE_L3##N
#define TREE_L3(f, idx, up, ...) \
TREE_L3_N(__VA_OPT__(,) __VA_ARGS__,_3,_2,_1,_0)(f, idx, up, __VA_ARGS__)
#define TREE_L2_NEXT(...) TREE_L3(__VA_ARGS__)
#define TREE_L2_VAL_IN(f, idx, up, a, b, c, ...) \
f(idx, a, b, c, up, IF_EMPTY(NOVALUE, idx+1 __VA_OPT__(,) __VA_ARGS__)) \
TREE_L2_NEXT(f, idx+1, idx __VA_OPT__(,) __VA_ARGS__)
#define TREE_L2_VAL(...) \
TREE_L2_VAL_IN(__VA_ARGS__)
#define TREE_L2_0(f, idx, up, a)
#define TREE_L2_1(f, idx, up, a) \
TREE_L2_VAL(f, idx, up, EXPAND a)
#define TREE_L2_2(f, idx, up, a, ...) \
TREE_L2_1(f, idx, up, a) \
TREE_L2_1(f, idx TREE_L2_NEXT(ADDONE,,,a), up, __VA_ARGS__)
#define TREE_L2_3(f, idx, up, a, ...) \
TREE_L2_1(f, idx, up, a) \
TREE_L2_2(f, idx TREE_L2_NEXT(ADDONE,,,a), up, __VA_ARGS__)
#define TREE_L2_N(_3,_2,_1,_0,N,...) \
TREE_L2##N
#define TREE_L2(f, idx, up, ...) \
TREE_L2_N(__VA_OPT__(,) __VA_ARGS__,_3,_2,_1,_0)(f, idx, up, __VA_ARGS__)
#define TREE_L1_NEXT(...) TREE_L2(__VA_ARGS__)
#define TREE_L1_VAL_IN(f, idx, up, a, b, c, ...) \
f(idx, a, b, c, up, IF_EMPTY(NOVALUE, idx+1 __VA_OPT__(,) __VA_ARGS__)) \
TREE_L1_NEXT(f, idx+1, idx __VA_OPT__(,) __VA_ARGS__)
#define TREE_L1_VAL(...) \
TREE_L1_VAL_IN(__VA_ARGS__)
#define TREE_L1_0(f, idx, up, a)
#define TREE_L1_1(f, idx, up, a) \
TREE_L1_VAL(f, idx, up, EXPAND a)
#define TREE_L1_2(f, idx, up, a, ...) \
TREE_L1_1(f, idx, up, a) \
TREE_L1_1(f, idx TREE_L1_NEXT(ADDONE,,,a), up, __VA_ARGS__)
#define TREE_L1_3(f, idx, up, a, ...) \
TREE_L1_1(f, idx, up, a) \
TREE_L1_2(f, idx TREE_L1_NEXT(ADDONE,,,a), up, __VA_ARGS__)
#define TREE_L1_N(_3,_2,_1,_0,N,...) \
TREE_L1##N
#define TREE_L1(f, idx, up, ...) \
TREE_L1_N(__VA_OPT__(,) __VA_ARGS__,_3,_2,_1,_0)(f, idx, up, __VA_ARGS__)
// -----------------------------------
#define TREE_SIZE(...) 0 TREE_L1(ADDONE, 0, NOVALUE, __VA_ARGS__)
#define TREE(...) TREE_L1(TREE_VAL, 0, NOVALUE, __VA_ARGS__)
// -----------------------------------
#define LIST \
(10, -3, 8, \
(-1, -1, 13, \
(0, -7, 15)), \
(-4, 14, 13)), \
(17, 0, 1), \
(3, 3, 3, \
(1, 1, 0)) \
/* */
// -----------------------------------
#include <stdio.h>
#include <string.h>
struct array_s {
int a;
int b;
int c;
unsigned int top;
unsigned int first;
};
static const struct array_s array[] = { TREE(LIST) };
static const char *snovalue(char *buf, unsigned v) {
if (v == NOVALUE) {
strcpy(buf, "NoValue");
} else {
sprintf(buf, "%u", v);
}
return buf;
}
#define SNOVALUE(v) snovalue((char[200]){0}, v)
int main() {
for (int i = 0; i < sizeof(array)/sizeof(*array); ++i) {
const struct array_s *const e = &array[i];
printf("[%d]={%2d,%2d,%2d,%10s,%10s},\n",
i, e->a, e->b, e->c, SNOVALUE(e->top), SNOVALUE(e->first));
}
}
将
array[]
生成的 TREE(LIST)
的内容输出为:
[0]={10,-3, 8, NoValue, 1},
[1]={-1,-1,13, 0, 2},
[2]={ 0,-7,15, 1, NoValue},
[3]={-4,14,13, 0, NoValue},
[4]={17, 0, 1, NoValue, NoValue},
[5]={ 3, 3, 3, NoValue, 6},
[6]={ 1, 1, 0, 5, NoValue},