【问题标题】:What is the need of defining an Enum/Struct by way of macros?通过宏定义 Enum/Struct 需要什么?
【发布时间】:2013-02-13 12:49:24
【问题描述】:

我指的是来自开源项目 tig 的代码示例。这是一个很棒的工具!

文件:tig.c

我正在努力寻找如下定义 request 枚举的原因:

enum request {
#define REQ_GROUP(help)
#define REQ_(req, help) REQ_##req

        /* Offset all requests to avoid conflicts with ncurses getch values. */
        REQ_UNKNOWN = KEY_MAX + 1,
        REQ_OFFSET,
        REQ_INFO,

        /* Internal requests. */
        REQ_JUMP_COMMIT,

#undef  REQ_GROUP
#undef  REQ_
};

甚至还有结构..

static const struct request_info req_info[] = {
#define REQ_GROUP(help) { 0, NULL, 0, (help) },
#define REQ_(req, help) { REQ_##req, (#req), STRING_SIZE(#req), (help) }
        REQ_INFO
#undef  REQ_GROUP
#undef  REQ_
};

可以看出REQ_GROUP 已被#defined 多次造成混乱.. 至少对我而言。好吧,我知道这样做可能有充分的理由.. 使用宏在代码中隐藏枚举/结构定义的实际原因是什么?

【问题讨论】:

  • 为了了解发生了什么,我经常发现使用 gcc 选项 -dNI -E 编译源代码很有用,这会产生预处理的源代码,但会显示宏定义,而不会扩展宏并且 #include 语句完好无损。
  • 下面的答案都有。这种策略的通用名称是“X 宏”,维基百科有一个关于它的页面:en.wikipedia.org/wiki/X_Macro 和 Dobbs 博士一样:drdobbs.com/cpp/the-x-macro/228700289
  • @Vicky drdobbs 链接是一颗宝石!谢谢!

标签: c++ c macros struct enums


【解决方案1】:

当应该对同一数据源使用不同的处理时,这通常会下降。

例如,你可以这样做:

#define MY_LIST X(Elem1) X(Elem2) X(Elem3)

然后:

enum MyEnum {
# define X(e) e,

  MY_LIST

  Last

# undef X
};

在这种情况下,MY_LIST 使用X当前 定义扩展。

现在,在同一个文件中,我也可以使用MY_LIST 创建一个to_string 方法

char const* to_string(MyEnum e) {
    switch(e) {
#       define X(e) case e: return #e;

        MY_LIST

        case Last: return "Last";

#       undef X
    }
    return 0;
} // to_string

这样,枚举值的集合只被写入一次,并且枚举和处理它的许多方法都会自动与这个集合保持同步。

【讨论】:

    【解决方案2】:

    这是为了避免请求列表的重复。该列表只需要在一处维护,REQ_INFO 的定义,枚举和数据结构是通过REQ_GROUPREQ_ 的适当定义从该列表自动生成的。

    如果没有这些宏,枚举和数据结构将不得不分开维护,注意保持它们彼此一致,这涉及到更多的工作和更大的错误范围。

    【讨论】:

      【解决方案3】:

      您错过了同一文件中的重要定义:

      #define REQ_INFO \
      REQ_GROUP("View switching") \
      VIEW_INFO(VIEW_REQ), \
      \
      REQ_GROUP("View manipulation") \
      REQ_(ENTER, "Enter current line and scroll"), \
      REQ_(NEXT, "Move to next"), \
      REQ_(PREVIOUS, "Move to previous"), \
      < output omitted as it is too long >
      

      因此,例如,您显示的结构扩展为:

      static const struct request_info req_info[] = {
         { 0, NULL, 0, "View switching" },
         < VIEW_INFO also expands to some long structure that was ommited here >
         { 0, NULL, 0, "View manipulation" },
         { REQ_ENTER, ENTER, STRING_SIZE("ENTER"), "Enter current line and scroll"},
         { REQ_NEXT, NEXT, STRING_SIZE("NEXT"), "Move to next"}
         < and so on >
      };
      

      正如其他答案所提到的,这样做主要是为了保持多个结构/枚举器同步。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-05
        • 1970-01-01
        • 2013-01-14
        • 1970-01-01
        • 1970-01-01
        • 2017-06-07
        相关资源
        最近更新 更多