如何在C中使用宏命名枚举?

ccgok5k5  于 2023-04-29  发布在  其他
关注(0)|答案(2)|浏览(96)

我有一个包含数百个宏的库,格式如下:

#define EVENT_A 0
#define EVENT_B 1
#define EVENT_C 2
...

但是,我想简化这个过程,以便轻松地更改“EVENT_”前缀。
我可以嵌套宏,使其更好,并允许轻松定义多个事件集:

#define DEFINE_EVENT(name,value)   EVENT_##name = value

DEFINE_EVENT(A, 0)
DEFINE_EVENT(B, 1)
DEFINE_EVENT(C, 2)

但我也希望前缀EVENT_由宏控制,以便在以后使用事件宏的字符串化版本时更容易。类似于以下的(不起作用)

#define EVENT_PREFIX               "EVENT_"
#define DEFINE_EVENT(name,value)   EVENT_PREFIX##name = value

DEFINE_EVENT(A, 0)
DEFINE_EVENT(B, 1)
DEFINE_EVENT(C, 2)

是否可以在DEFINE_EVENT宏中使用EVENT_PREFIX宏来帮助命名事件?
因为你不能用其他宏创建宏,所以我编辑了这个问题,利用宏来命名枚举。如果我创建一个枚举如下:

#define DEFINE_EVENT(name, value)   EVENT_##name = value,
enum {
    #include "events.txt"
};
#undef DEFINE_EVENT

以下是events.txt

DEFINE_EVENT(A,0)
DEFINE_EVENT(B,1)
DEFINE_EVENT(C,2)

是否可以为EVENT_PREFIX添加一个宏?就像

#define EVENT_PREFIX     "EVENT_"
#define DEFINE_EVENT(name, value)   EVENT_PREFIX##name = value,
enum {
    #include "events.txt"
};
#undef DEFINE_EVENT
z3yyvxxp

z3yyvxxp1#

##操作器直接连接两个令牌--这些令牌本身是否是宏并不重要,因为在连接之前不会发生任何扩展。如果你想在连接之前展开宏,你需要多个宏来控制

#define CONCAT(A,B)                A##B
#define EXPAND_CONCAT(A,B)         CONCAT(A,B)
#define EVENT_PREFIX               EVENT_
#define DEFINE_EVENT(name,value)   EXPAND_CONCAT(EVENT_PREFIX, name) = value

这里的CONCAT宏只是直接连接两个令牌(使用##)。EXPAND_CONCAT宏将首先展开其参数中的所有宏,然后将结果连接起来。
另外请注意,您不希望EVENT_周围加引号,因为那样会使其成为字符串而不是名称,并干扰连接

bxjv4tth

bxjv4tth2#

正确使用“X宏”应该是这样的:

#include <stdio.h>

// list of all postfix names and their corresponding values:
#define POSTFIX_LIST(X) \
  X(A,   0) \
  X(B,  42) \
  X(C, 666) \

typedef enum
{
  #define CREATE_EVENT_ENUM(postfix, val) EVENT_##postfix = val, 
  // run the above macro for every item in the list:
  POSTFIX_LIST(CREATE_EVENT_ENUM)
} event_t;

int main (void)
{
  printf("%d\n", EVENT_A);
  printf("%d\n", EVENT_B);
  printf("%d\n", EVENT_C);
}

如果你想要一个变量前缀,那么你必须按照@Chris Dodd的回答做--在应用##之前扩展宏。这是因为##是在宏内部的任何宏扩展之前由预处理器进行评估的。示例:

#include <stdio.h>

#define PREFIX EVENT_
#define POSTFIX_LIST(X) \
  X(A,   0) \
  X(B,  42) \
  X(C, 666) \

#define CONCAT(x,y) x ## y
#define EXPAND_CONCAT(x,y) CONCAT(x,y)

typedef enum
{
  #define CREATE_ENUM(postfix, val) EXPAND_CONCAT(PREFIX, postfix) = val,
  POSTFIX_LIST(CREATE_ENUM)
} event_t;

int main (void)
{
  printf("%d\n", EVENT_A);
  printf("%d\n", EVENT_B);
  printf("%d\n", EVENT_C);
}

从那里开始,“字符串化”可以类似地完成,因为#在扩展方面与##的工作方式相同。虽然在“字符串化”中,我们可以利用字符串字面量在稍后的预处理器翻译阶段自动连接,所以不需要使用##

#define STR_CONCAT(x,y) #x #y  // this becomes "EVENT_" "A"  etc then -> "EVENT_A"
#define EXPAND_STR_CONCAT(x, y) STR_CONCAT(x,y)

const char str_list[][100] =
{
  #define STRINGIFY(postfix, val) EXPAND_STR_CONCAT(PREFIX, postfix),
  POSTFIX_LIST(STRINGIFY)
};
for(size_t i=0; i<3; i++)
  puts(str_list[i]);

相关问题