【问题标题】:Counting preprocessor macros计数预处理器宏
【发布时间】:2011-12-28 23:22:12
【问题描述】:

我有这个宏代码,它允许我使用一个构造将 C 枚举和枚举名称列表定义为字符串。它使我不必重复枚举器名称(并可能为大型列表引入错误)。

#define ENUM_DEFINITIONS(F) \
  F(0, Item1) \
  F(5, Item2) \
  F(15, Item3) \
  ...
  F(63, ItemN)

然后:

enum Items {
  #define ITEM_ENUM_DEFINE(id, name) name = id,
    ENUM_DEFINITIONS(ITEM_ENUM_DEFINE)
  #undef ITEM_ENUM_DEFINE

当展开时,应该产生:

enum Items {
  Item1 = 0,
  Item2 = 5,
  Item3 = 15,
  ...
  ItemN = 63,
}

在实现文件中,我有这样的代码:

const char* itemNames[TOTAL_ITEMS];
int iter = 0;

#define ITEM_STRING_DEFINE(id, name) itemNames[iter++] = #name;
  ENUM_DEFINITIONS(ITEM_STRING_DEFINE)
#undef ITEM_STRING_DEFINE

当展开时,会产生:

itemNames[iter++] = "Item1";
itemNames[iter++] = "Item2";
itemNames[iter++] = "Item3";
...
itemNames[iter++] = "ItemN";

我想知道我以这种方式创建了多少枚举项,并能够将其传递给编译时数组。在上面的示例中,这将在编译时确定 TOTAL_ITEMS = N。是否可以以这种方式计算宏调用?

我看到有人提到非标准的 COUNTER 宏,类似于 FILELINE 宏,但我希望还有一种更标准的方法。

也有兴趣了解是否有更好的方法来实现这一点而无需使用宏。

【问题讨论】:

  • 为什么需要enum 和字符串数组?
  • 这似乎在我的工作中经常出现。一个示例是枚举状态的状态机,前端 GUI 显示当前状态的名称。只定义一次很方便,也方便其他希望添加新状态的开发人员。

标签: c macros c-preprocessor


【解决方案1】:

以下应该有效:

#define ITEM_STRING_DEFINE(id, name) #name, // note trailing comma
const char *itemNames[] = {
  ENUM_DEFINITIONS(ITEM_STRING_DEFINE)
};

#define TOTAL_ITEMS (sizeof itemNames / sizeof itemNames[0])

编辑:感谢 Raymond Chen 指出我们不必担心列表中不必要的最后逗号。 (我一直误解了具有严格 C89 编译器的枚举问题,如 Is the last comma in C enum required?。)

【讨论】:

  • 你不需要吃结尾的逗号。结尾的逗号是合法的并且被忽略。
  • 关于最后不必要的逗号,我似乎记得 SGI Irix 编译器会发出一个不可抑制的警告,这迫使我总是省略它。
【解决方案2】:

您可以使用相同的技术来计算调用次数。

enum itemscounter  { 
  #define ITEM_ENUM_DEFINE(id, name) name##counter,
    ENUM_DEFINITIONS(ITEM_ENUM_DEFINE) 
  #undef ITEM_ENUM_DEFINE 
 TOTAL_ITEMS
};

【讨论】:

  • 我接受了上述答案,但认为这也是一个很好(也很聪明)的方法。谢谢!
【解决方案3】:

也有兴趣了解是否有更好的方法来实现这一点而无需使用宏。

您始终可以使用 ruby​​ 或 python 等脚本语言为您生成 .c 和 .h 文件。如果你做得好,你可以将你的脚本集成到你的 Makefile 中。

【讨论】:

  • 我通常不喜欢在构建要求中添加另一种语言的方法。
【解决方案4】:

我知道这不是一个完整的答案。 你可以围绕这样的东西创建一个宏。

#include <stdio.h>

const char * array[] = {
  "arr1", "arr2", "arr3", "arr4"
};

int main (int argc, char **argv)$
{
  printf("%d\n", sizeof(array)/sizeof(const char *));
}

如果你可以修改你的枚举,让它有连续的元素,你可以这样做(来自 Boost)

enum { A=0,B,C,D,E,F,N };
const char arr[N]; // can contain a character for each enum value

【讨论】:

    【解决方案5】:

    见建议沐动力'Enums, Strings and Laziness';这些至少与你所追求的有关。

    否则,请查看 Boost Preprocessor 集合(可用于 C 预处理器和 C++ 预处理器)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-04-15
      • 2015-07-31
      • 1970-01-01
      • 2010-09-19
      • 2020-02-09
      • 1970-01-01
      • 2011-01-26
      相关资源
      最近更新 更多