计算预处理器宏

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 宏,类似于 FILE 和 LINE 宏,但我希望有更标准的方法。
如果不使用宏,是否有更好的方法来实现这一点,也很感兴趣听听。

为什么需要同时使用“枚举”和字符串数组? - Philip
在我的工作中,这似乎经常出现。例如,状态机的状态被枚举,并且前端GUI显示当前状态的名称。只定义一次很方便,也更容易让其他开发人员添加新状态。 - Eyal
5个回答

11
以下内容应该可行:
#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])

编辑:感谢雷蒙德·陈指出我们不必担心列表中的不必要的最后逗号。(我之前记错了与严格C89编译器中的枚举相关的问题,如C枚举中的最后一个逗号是否是必需的?)。


1
你不需要吃掉末尾的逗号。末尾的逗号是合法的并且会被忽略。 - Raymond Chen
关于最后一个不必要的逗号,我记得 SGI Irix 编译器会发出一个无法抑制的警告,这迫使我总是省略它。 - Joseph Quinsey

6

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

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

1
我接受了上面的答案,但是我认为这也是一个相当不错(且聪明)的方法。谢谢! - Eyal

1
也很想听听是否有更好的方法来实现这一点,而不必使用宏。
您可以始终使用脚本语言,如Ruby或Python为您生成.c和.h文件。如果做得好,您可以将脚本集成到Makefile中。

2
我通常不喜欢采用需要增加构建要求语言的方法。 - Alexander Oh

1

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

#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

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接