如何在C中创建结构文字的数组文字?

时间:2019-01-09 15:49:21

标签: c struct initialization lvalue

我的目标是自动生成老式的基于知识的系统的控制逻辑,该系统本质上是一系列数百个结构类似的if-then语句。我们还希望通过一种反射来了解这些语句的属性,数组文字有助于生成这些反射。

我在这里回顾了许多关于SO的答案,但是其中大多数是关于字符串文字数组的,这不是我想要实现的。

我正在尝试制作一个X宏,它包含一个结构文字数组作为其参数之一,可用于初始化堆栈分配的数组变量。

以下一些未编译的代码表明了我的尝试:

#include <stdio.h>

typedef enum qty_t {
    qty_None, qty_Some, qty_Many    
} qty_t;

typedef enum arg_t {
    arg_X, arg_Y, arg_Z
} arg_t;

typedef struct action_t {
    int id;
    qty_t quantity;
    arg_t argument;
} action_t;

/* a change is a sequence of actions, and a change identifier */
/* the outermost {} are the array, the inner ones being the structs */
#define CHANGES \
CHANGE(1, ({{.id=1,.quantity=qty_None,.argument=arg_X}, \
            {.id=2,.quantity=qty_Many,.argument=arg_Z}\
            }\
        )\
    )\
CHANGE(2, ({{1,qty_Some,arg_Y}}))

int main(void) {
    // your code goes here
#define CHANGE(change_id, actions) \
    action_t current_actions ## change_id[] = actions;

    CHANGES

#undef CHANGE
    return 0;
}

如何将结构文字的数组文字放入CHANGE宏中,特别是可用于初始化current_actions1变量的数组文字?

2 个答案:

答案 0 :(得分:2)

那呢:

#define CHANGES \
CHANGE(1, {{.id=1,.quantity=qty_None,.argument=arg_X}, \
            {.id=2,.quantity=qty_Many,.argument=arg_Z}\
            }\
           \
    )\
CHANGE(2, {{.id=1,.quantity=qty_Some,.argument=arg_Y}})

int main(void) {
    // your code goes here
#define CHANGE(change_id, actions ...) \
    action_t current_actions ## change_id[] = actions;

    CHANGES

#undef CHANGE
    return 0;
}

我在CHANGES中删除了括号,并在CHANGE中添加了...

经过编译,gcc -E foo.c给出:

   int main(void) {




        action_t current_actions1[] = {{.id=1,.quantity=qty_None,.argument=arg_X}, {.id=2,.quantity=qty_Many,.argument=arg_Z} }; action_t current_actions2[] = {{.id=1,.quantity=qty_Some,.argument=arg_Y}};


        return 0;
    }

答案 1 :(得分:2)

没有“结构体文字数组”之类的东西,无论文字本身与否。数组的元素可以是结构,您可以使用结构文字来初始化结构数组(yuck)的元素(包括数组文字),但数组的元素本身不是文字。这听起来可能确实-可能是 -是学究的,但是使用一致且正确的术语可以提高思想和沟通的清晰度。

实际上,您根本没有使用结构文字或数组文字。您只需在用于数组结构的初始化程序中使用struct initializers 。这样已经简化了这个问题。

代码的第一个问题是在数组初始化程序周围的宏CHANGE定义中放置的括号。这些是CHANGE宏的每次调用的第二个参数的一部分,因此,它们作为宏CHANGES的替换文本的一部分发出。但是它们不是初始化器允许的语法的一部分,因此生成的代码无效。

我想首先要放在括号内,以避免初始化程序内部的逗号被解释为分隔宏参数。解决此问题的另一种方法(在这种情况下,至少要这样)是使您定义CHANGE宏可变参数:

#define CHANGE(change_id, ...) \
    action_t current_actions ## change_id[] = __VA_ARGS__;

使用C99中引入的标准形式的可变参数宏,这为我解决了问题。

另一个更结构化的选择是为结构初始化程序添加宏,以使内部及其之间的逗号不影响宏参数的标识。例如,

#define FIRST_ACTION(i,q,a) {.id=i,.quantity=q,.argument=a}
#define ACTION(i,q,a) ,FIRST_ACTION(i,q,a)

#define CHANGES \
CHANGE(1, {\
    FIRST_ACTION(1,qty_None,arg_X)\
    ACTION(2,qty_Many,arg_Z)\
})\
CHANGE(2, {\
    FIRST_ACTION(1,qty_Some,arg_Y)\
})

// ...

#define CHANGE(change_id, actions) \
    action_t current_actions ## change_id[] = actions;

    CHANGES

当然,所有这一切都假定您的案例中的X宏方法有一些不错的价值。这至少需要在代码中的其他地方使用CHANGES宏。在您呈现的内容中,没有任何明显的事物,但可以将其省略。不过,我目前还不清楚,您特定的CHANGES宏提供了其他用途,而使用其他方法无法更好地解决此问题。