删除生成器宏

时间:2017-07-11 07:30:40

标签: c gcc enums c-preprocessor

我目前正在开发一个包含大量枚举的代码库。需要将enum值转换为字符串表示形式。要做到这一点,有一堆辅助宏可以在窗体

上的宏上运行
#define THINGS_MAP(G, P) \
    G(LAMP, P) \
    G(DESK, P)

代码中的其他地方有一些宏大致如下:

#define MK_ENUM(SYM, P) P##_##SYM,
enum { THINGS_MAP(MK_ENUM, THING) }; /* expands to { THING_LAMP, THING_DESK, } */

我希望避免在枚举中更改MK_ENUMTHINGS_MAP的调用。

但是,我现在有一个特别长的enum列表,我还需要在条目中添加一些分类。所以我在想做像

这样的事情
#define THINGS_PROP_MAP(G, P) \
    G(LAMP, WOODEN, P) \
    G(DESK, METALIC, P)

但是,由于我的所有辅助宏都需要传递两个参数,而不是三个,我在想是否可以映射某种丢弃参数的宏。这可能吗?

我正在寻找的是:

#define THINGS_PROP_MAP(G, P) \
    G(LAMP, WOODEN, P) \
    G(DESK, METALIC, P)

/* DROP_PROP should create G(LAMP, P) G(DESK, P) */
#define THINGS_MAP(G, P) DROP_PROP(THINGS_PROP_MAP)

我的一个想法是添加额外的转换步骤,但我没有让它工作

#define THINGS_PROP_MAP(G, T, P) \
    G(T(LAMP, WOODEN, P)) \
    G(T(DESK, METALIC, P))
#define DROP_PROP(SYM, _ , P) SYM, P
#define THING_MAP(G, P) THING_PROP_MAP(G, DROP_PROP, P)

是的,我知道这不仅仅是宏观滥用等等了: - )

1 个答案:

答案 0 :(得分:3)

您的宏很好,但是您的#define MK_ENUM(SYM, P) P##_##SYM,需要两个参数,其中此调用G(T(LAMP, WOODEN, P))例如G = MK_ENUM仅使用一个参数调用G,即使内部语句会扩展到LAMP, P

要强制预处理器执行一个额外的扩展步骤并确认LAMP, P不是单个令牌,您必须添加:

#define MK_ENUM_EXPAND(...) MK_ENUM(__VA_ARGS__)

然后使用:

enum { THING_MAP(MK_ENUM_EXPAND, THING) };

请注意,您的宏不会扩展为enum { THING_LAMP, THING_DESK };,但会在enum { THING_LAMP, THING_DESK, };的末尾添加逗号。

完整的工作代码:

#define MK_ENUM(SYM, P) P##_##SYM,
#define MK_ENUM_EXPAND(...) MK_ENUM(__VA_ARGS__)

#define THINGS_PROP_MAP(G, T, P) \
    G(T(LAMP, WOODEN, P)) \
    G(T(DESK, METALIC, P))

#define DROP_PROP(SYM, _ , P) SYM, P

#define THINGS_MAP(G, P) THINGS_PROP_MAP(G, DROP_PROP, P)

enum { THINGS_MAP(MK_ENUM_EXPAND, THING) }; /* expands to { THING_LAMP, THING_DESK, } */

要测试宏扩展,将gcc与命令行参数-E一起使用非常有用:

$ gcc -E srcFile.c

因为您收到具体的错误消息并了解出现了什么问题。

如果您不想在枚举中更改MK_ENUMTHINGS_MAP,则可以执行以下操作:G##S THINGS_PROP_MAP G = MK_ENUM {1}}和S = _EXPAND

#define MK_ENUM(SYM, P) P##_##SYM,
#define MK_ENUM_EXPAND(...) MK_ENUM(__VA_ARGS__)

#define THINGS_PROP_MAP(G, S, T, P) \
    G##S(T(LAMP, WOODEN, P)) \
    G##S(T(DESK, METALIC, P))

#define DROP_PROP(SYM, _ , P) SYM, P

#define THINGS_MAP(G, P) THINGS_PROP_MAP(G, _EXPAND, DROP_PROP, P)

enum { THINGS_MAP(MK_ENUM, THING) }; /* expands to { THING_LAMP, THING_DESK, } */