我的目标是自动生成老式的基于知识的系统的控制逻辑,该系统本质上是一系列数百个结构类似的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变量的数组文字?
答案 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
宏提供了其他用途,而使用其他方法无法更好地解决此问题。