我在下面有这个结构
struct foo {
char *name;
int (*validate)(u8_t *data, size_t size);
u8_t value;
u8_t changed;
foo_id id;
};
typedef struct foo foo_t;
我希望在编译时通过定义创建一个foo_t数组,如下所示:
int my_validate(u8_t *data, size_t size) {...}
FOO_CREATE(my_name, my_validate, 0, 0);
FOO_CREATE(my_name2, NULL, 0, 0);
并且在编译时结果为:
enum {
MY_NAME_FOO = 0,
MY_NAME2_FOO,
FOO_COUNT
} foo_id;
static foo_t foo[FOO_COUNT] = {
{
.name = "my_name",
.validate = my_validate,
.value = 0,
.changed = 0,
.id = MY_NAME_FOO
},
{
.name = "my_name2",
.validate = NULL,
.value = 0,
.changed = 0,
.id = MY_NAME2_FOO
},
}
如果仅用C和cmake在编译时不可能做到这一点,那么您对我有什么建议呢?
我要建议您的是我在一个真正的大型生产项目中实际看到的东西。我不得不说这是因为我承认这不是一个[[nice looking解决方案。
.h
扩展名或具有描述性扩展名的内容,例如.def
。因此,
PreprocessorTypePopulation.h
可以定义如下:FOO_CREATE(my_name, my_validate, 0, 0)
FOO_CREATE(my_name2, NULL, 0, 0)
它包含所有调用的FOO_CREATE
宏。Note:每次宏调用后都没有逗号或分号。在这种情况下,也可以使用逗号(从宏中删除它们)实现(因为仅涉及枚举项和数组元素)。
包含生成的结构体/枚举的文件:这可以是
.h
文件。在我的示例中,它是C文件,其中包含伪指令main()
。我只是将OP的int类型转换为stdint.h
中包含的类型。
#include <stddef.h> #include <stdint.h> #ifdef FOO_CREATE #undef FOO_CREATE #endif /* Enum creation macro */ #define FOO_CREATE(nm,func,val,chgd) nm##_FOO, typedef enum { #include "PreprocessorTypePopulation.h" FOO_COUNT } foo_id; struct foo { char *name; int (*validate)(uint8_t *data, size_t size); uint8_t value; uint8_t changed; foo_id id; }; typedef struct foo foo_t; int my_validate(uint8_t *data, size_t size) { return 0; } #undef FOO_CREATE /* Array creation macro */ #define FOO_CREATE(nm,func,val,chgd) \ { \ .name = (char *) #nm, \ .validate = func, \ .value = val, \ .changed = chgd, \ .id = nm##_FOO \ }, static foo_t foo[FOO_COUNT] = { #include "PreprocessorTypePopulation.h" }; int main(void) { return 0; }
如您所见,已实施以下策略:先前的任何
- Undef
FOO_CREATE()
定义为第一个任务(枚举生成)定义FOO_CREATE()
宏.def
文件FOO_CREATE()
的顺序将用于根据刚刚定义的宏生成枚举项.def
文件FOO_CREATE()
的序列将根据刚刚定义的宏用于生成数组元素-输出
仅预处理器
选项编译,对于我来说是gcc PreprocessorTypePopulation.c -E -P
([),然后获得以下输出(我刚刚删除了与所包含的标准标题相关的所有内容):-P
选项从输出中删除linemarkers
typedef enum {
my_name_FOO,
my_name2_FOO,
FOO_COUNT
} foo_id;
struct foo {
char *name;
int (*validate)(short *data, int size);
short value;
short changed;
foo_id id;
};
typedef struct foo foo_t;
int my_validate(short *data, int size)
{
return 0;
}
static foo_t foo[FOO_COUNT] = {
{ .name = "my_name", .validate = my_validate, .value = 0, .changed = 0, .id = my_name_FOO },
{ .name = "my_name2", .validate = NULL, .value = 0, .changed = 0, .id = my_name2_FOO },
}
int main(void)
{
return 0;
}
-结论,不一定是一个不错的解决方案。但是它起作用,它可以防止很多人为的错误将多个定义集中在一个文件中。在长期的大型项目中,这可以节省数周的工作。