删除生成器宏中的参数

Kot*_*tte 6 c enums gcc c-preprocessor

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

#define THINGS_MAP(G, P) \
    G(LAMP, P) \
    G(DESK, P)
Run Code Online (Sandbox Code Playgroud)

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

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

我想避免更改MK_ENUMTHINGS_MAP枚举内部的调用.

但是,我现在有一个特别长的enum列表,我还需要在条目中添加一些分类.所以我在考虑做类似的事情

#define THINGS_PROP_MAP(G, P) \
    G(LAMP, WOODEN, P) \
    G(DESK, METALIC, P)
Run Code Online (Sandbox Code Playgroud)

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

我正在寻找的东西是:

#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)
Run Code Online (Sandbox Code Playgroud)

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

#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)
Run Code Online (Sandbox Code Playgroud)

是的,我知道这是超出宏观滥用等等:-)

And*_*ing 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__)
Run Code Online (Sandbox Code Playgroud)

然后使用:

enum { THING_MAP(MK_ENUM_EXPAND, THING) };
Run Code Online (Sandbox Code Playgroud)

进一步注意,您的宏不会扩展为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, } */
Run Code Online (Sandbox Code Playgroud)

要测试宏扩展,使用 gcc 和命令行参数很有用-E

$ gcc -E srcFile.c
Run Code Online (Sandbox Code Playgroud)

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


如果您不想更改MK_ENUM和对枚举内部的调用,THINGS_MAP您可以执行以下操作,我只是G##STHINGS_PROP_MAPwhereG = MK_ENUM和中连接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, } */
Run Code Online (Sandbox Code Playgroud)