我想要一个宏
#define MY_STRUCT( /* ... /*) /* ... */
我想这样称呼它
MY_STRUCT(point, double x, int y);
扩展到这个
typedef struct {
double x;
int y;
} point;
void init_point(point *p) {
p->x = load_double_from_somewhere();
p->y = load_int_from_somewhere();
}
宏应该能够处理我给予它的任意数量的参数。我尝试通过宏自动生成模型对象的数据绑定,因为我一直在手工编写Map函数,这很烦人且重复(从XML到C结构)。我知道这是可能的,但我不知道如何实现。
4条答案
按热度按时间htzpubme1#
***注意:***我只是在解决如何编写
struct
定义的问题。我没有找到一种方法来让预处理器自动生成序列化和反序列化代码,原因有两个。首先,不可能从宏参数中提取标记--成员名称--即使您知道要提取哪个标记。其次,您可以使用C11的_Generic
特性来创建对预定义类型特定的序列化/反序列化函数的调用。但是_Generic
调用需要一个完整的可能性列表,因此不可能逐步地构建这些可能性。我想您会发现,自动生成序列化/反序列化代码的现有系统依赖于外部代码生成器。这是一个灵活得多(可能也更容易)的策略。那么,回到自动生成结构声明。正如前面提到的,只有生成 N 个宏,每个宏对应一个参数,这才是真正可能的。而且,你还需要一种计算 N 的方法,这可能需要更多自动生成的宏。总而言之,使用像Jens Gustedt的P99这样的框架要容易得多。
下面是一个高度简化的示例,说明了如何执行此操作,由于模式很明显,因此字段数量有限。
我们从一个宏开始,它将计算变量调用中的参数个数。注意,如果没有变量参数,它将正确地返回0。一个健壮的解决方案,如P99,将正确地处理这个问题。但在这个例子中,这并不重要,因为没有成员的
struct
是C不允许的。所以我们知道这里至少有一个参数(在C++中不是这样的)。现在,我们需要8个宏来构造成员,它们所要做的就是在参数之间插入分号,所以这不是很有挑战性:
最后,我们需要把所有这些放在一起。为此,我们需要一个可以连接宏名称的宏:
最后,创建结构体的宏
现在我们可以给予一下:
下面是
gcc -E
在上述所有条件下生成的结果:(注意:我不能评论这是否适用于MSVC的不同版本,但它都是标准的C99。)2wnc66cl2#
我不知道你要它做什么,但是...
其结果是:
或
结果是
j9per5c43#
我不确定是否有可能从
double x
中提取x
(除非您知道变量可能具有的所有类型)。此外,使用预处理器迭代逗号分隔列表需要编写样板宏(我认为有
O(n)
个)。boost.preprocessor可能会对此有所帮助,但如果使用不同的语法,则完全可以避免样板宏:实施:
gcmastyq4#
如果你想自动生成源代码,预处理器是你能得到的最糟糕的工具。
而且你绝对不能创建任何宏来生成一个有任意个字段的结构体;C预处理器不支持循环或递归。
但是如果最多8个字段/参数就足够了,尽管NON-STANDARD,在gcc和clang中也可以:
这会故意创建一个
struct name { ... }
,而不是OP中的typedef struct { ... } name
:即使没有实际生成typedef
的MY_STRUCT
宏,它也已经够迟钝的了。