如何在编译时为我的结构动态创建一个枚举

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

我在下面有这个结构

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在编译时不可能做到这一点,那么您对我有什么建议呢?

c struct enums compilation c-preprocessor
1个回答
0
投票

我要建议您的是我在一个真正的大型生产项目中实际看到的东西。我不得不说这是因为我承认这不是一个[[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; }

如您所见,已实施以下策略:

  1. Undef
先前的任何FOO_CREATE()定义为第一个任务(枚举生成)定义FOO_CREATE()
  • 包括.def文件
  • INSIDE枚举。 FOO_CREATE()的顺序将用于根据刚刚定义的宏生成枚举项
  • 再次取消对宏的定义,然后将其重新定义为第二项任务(结构定义的数组)
  • 包括.def文件
  • INSIDE
  • 数组定义。 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; }
    -

    结论,不一定是一个不错的解决方案。但是它起作用,它可以防止很多人为的错误将多个定义集中在一个文件中。在长期的大型项目中,这可以节省数周的工作。

    © www.soinside.com 2019 - 2024. All rights reserved.