嵌套参数的递归宏

问题描述 投票:0回答:1

我想在编译时使用宏定义数据结构。数据结构看起来像:

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
是第一个子元素的数组索引。

c recursion c-preprocessor
1个回答
0
投票

以下代码:

#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},
© www.soinside.com 2019 - 2024. All rights reserved.