【问题标题】:Drop parameters in generator macro在生成器宏中删除参数
【发布时间】:2017-07-11 07:30:39
【问题描述】:

我目前正在开发一个包含大量枚举的代码库。需要将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)

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

【问题讨论】:

  • 是否有理由不使用外部脚本生成代码,比如 awk?例如,让定义枚举的头文件包含一个自动生成的头文件。在 Makefile 中实现自动化非常简单。如果您确实有很多枚举或需要大量宏魔术,则在外部生成定义,而不是使用复杂的宏魔术,应该更易于维护。
  • 嗯,回想起来,这可能是一个更好的主意:-)。随着时间的推移,代码变得越来越复杂。

标签: c gcc enums c-preprocessor


【解决方案1】:

您的宏很好,但您的 #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, } */

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

$ gcc -E srcFile.c

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


如果您不想更改MK_ENUM 和枚举内对THINGS_MAP 的调用,您可以执行以下操作,我只是在THINGS_PROP_MAP 中连接G##S,其中G = MK_ENUMS = _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, } */

【讨论】:

  • 我的问题可能有点不清楚,但问题是enum 宏已经定义,需要THING_MAP(G, P) 形式的内容,我想更改其余部分由于一个结构的特殊情况而导致的代码。但也许这个解决方案也适用于这种情况......
  • 您是在说:I would like to avoid changing these macros, if possible. 但在那之后,您将展示您更改THINGS_MAP 的尝试。我不确定您到底想要什么,所以请尝试解释并编辑您的问题,以便其他人或我能够给出准确的答案。
  • 如果可能的话,我只想更改THINGS_MAP 以使其可供MK_ENUM 使用。会澄清
  • 我添加了一个版本,避免更改您不想更改的内容。
猜你喜欢
  • 1970-01-01
  • 2018-09-06
  • 1970-01-01
  • 1970-01-01
  • 2014-05-08
  • 2022-11-15
  • 1970-01-01
  • 2016-09-18
  • 1970-01-01
相关资源
最近更新 更多