【问题标题】:Define array and symbolic indices at same time同时定义数组和符号索引
【发布时间】:2009-04-27 17:57:26
【问题描述】:

我试图想出一种聪明的方法(在 C 中)来创建一个字符串数组,以及数组索引的符号名称(枚举或#define),在一个易于维护的构造中。比如:

const char *strings[] = { M(STR_YES,“是”), M(STR_NO,“否”), M(STR_MAYBE,“也许”) };

结果相当于:

const char *strings[] = {"yes", "no", "maybe"}; 枚举索引 {STR_YES, STR_NO, STR_MAYBE}; (或#define STR_YES 0 等)

但在这种情况下,我对如何构造 M 宏一无所知。

有什么聪明的想法吗?

【问题讨论】:

    标签: c syntax


    【解决方案1】:

    clang 编译器源代码中使用的一种技术是创建 .def 文件,其中包含这样的列表,该列表的设计类似于 C 文件,无需接触使用它的其他代码文件即可轻松维护。例如:

    #ifndef KEYWORD
    #define KEYWORD(X)
    #endif
    #ifndef LAST_KEYWORD
    #define LAST_KEYWORD(X) KEYWORD(X)
    #endif
    
    KEYWORD(return)
    KEYWORD(switch)
    KEYWORD(while)
    ....
    LAST_KEYWORD(if)
    
    #undef KEYWORD
    #undef LAST_KEYWORD
    

    现在,它所做的就是包含这样的文件:

    /* some code */
    #define KEYWORD(X) #X, 
    #define LAST_KEYWORD(X) #X
    
    const char *strings[] = { 
    #include "keywords.def"
    };
    
    #define KEYWORD(X) kw_##X, 
    #define LAST_KEYWORD(X) kw_##X
    
    enum { 
    #include "keywords.def"
    };
    

    在你的情况下,你可以做类似的事情。如果您可以使用STR_yes、STR_no、... 作为枚举器名称,您可以使用与上述相同的方法。否则,只需通过宏两件事。一个小写名称和一个大写名称。然后你可以像上面那样将你想要的字符串化。

    【讨论】:

    • 这种技术称为 X-Macros - en.wikipedia.org/wiki/C_preprocessor#X-Macros
    • 完美,这就是我在周一缓慢迷惑的大脑中寻找的钩子……将定义放在一个单独的文件中,并阅读两次。谢谢!
    • 这种技术的一个缺点是 IDE 和/或调试器可能不够聪明,无法正确解析这些。如果是这种情况 - 生成列表作为构建过程的一部分可能会更好。
    【解决方案2】:

    这是使用代码生成的好地方。使用 perl、php 之类的语言来生成您的 .h 文件。

    【讨论】:

      【解决方案3】:

      不需要将其放入特定的 .def 文件中;仅使用预处理器是完全可能的。我通常定义一个名为...LIST 的列表,其中每个元素都包含在...LIST_ELEMENT 中。根据我将使用列表的内容,我将只用逗号分隔除最后一个条目(最简单)之外的所有条目,或者在一般情况下,可以在每次使用时单独选择分隔符。示例:

      #include <string.h>
      
      #define DIRECTION_LIST \
      DIRECTION_LIST_ELEMENT( up,    DIRECTION_LIST_SEPARATOR ) \
      DIRECTION_LIST_ELEMENT( down,  DIRECTION_LIST_SEPARATOR ) \
      DIRECTION_LIST_ELEMENT( right, DIRECTION_LIST_SEPARATOR ) \
      DIRECTION_LIST_ELEMENT( left,  NO_COMMA )
      
      #define COMMA ,
      #define NO_COMMA /**/
      
      #define DIRECTION_LIST_ELEMENT(elem, sep) elem sep
      #define DIRECTION_LIST_SEPARATOR COMMA
      typedef enum {
          DIRECTION_LIST
      } direction_t;
      #undef DIRECTION_LIST_ELEMENT
      #undef DIRECTION_LIST_SEPARATOR
      
      #define DIRECTION_LIST_ELEMENT(elem, sep) void (*move_ ## elem)(struct object_s * object);
      #define DIRECTION_LIST_SEPARATOR NO_COMMA
      typedef struct object_s {
          char *name;
          // ...
          DIRECTION_LIST
      } object_t;
      #undef DIRECTION_LIST_ELEMENT
      #undef DIRECTION_LIST_SEPARATOR
      
      static void move(object_t *object_p, const char * direction_string)
      {
          if (0) {
          }
      #define DIRECTION_LIST_SEPARATOR NO_COMMA
      #define DIRECTION_LIST_ELEMENT(elem, sep) \
          else if (strcmp(direction_string, #elem) == 0) { \
              object_p->move_ ## elem(object_p); \
          }
          DIRECTION_LIST
      #undef DIRECTION_LIST_ELEMENT
      #undef DIRECTION_LIST_SEPARATOR
      }
      

      【讨论】:

        猜你喜欢
        • 2012-12-08
        • 2011-01-27
        • 2023-04-02
        • 2012-10-24
        • 2021-12-08
        • 2022-12-03
        • 1970-01-01
        • 2014-05-15
        • 1970-01-01
        相关资源
        最近更新 更多