我目前正在开发一个包含大量枚举的代码库。需要将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_ENUM
和THINGS_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)
是的,我知道这不仅仅是宏观滥用等等了: - )
答案 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_ENUM
和THINGS_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, } */