能否在C语言中组合多组宏列表以生成包含所有可能组合的枚举类型?
能否在C语言中组合多组宏列表以生成包含所有可能组合的枚举类型?
当然可以!C语言的预处理器虽然语法有点“硬核”,但完全能实现这种多组宏的笛卡尔积来生成所有可能的枚举项。我给你一步步拆解怎么实现你要的效果。
核心思路是利用预处理器的递归展开特性,逐层遍历每组宏的元素,再智能拼接成枚举标识符,同时还要处理你宏列表里的空项(比如R()、P()),避免生成多余的下划线。
下面是完整的实现代码:
// 辅助宏:处理空参数,把空的宏参数转换成空字符串 #define EMPTY() #define GET_EMPTY(x) _GET_EMPTY(x) #define _GET_EMPTY(x) __GET_EMPTY(x, ) #define __GET_EMPTY(x, y) y // 辅助宏:安全拼接标识符,处理其中一个为空的情况 #define CONCAT(a, b) _CONCAT(a, b) #define _CONCAT(a, b) a##b // 辅助宏:如果前一个参数非空,就用下划线连接两个标识符;如果为空,直接取后一个 #define JOIN(a, b) _JOIN(a, b) #define _JOIN(a, b) IF_EMPTY(a, b, CONCAT(a, _##b)) #define IF_EMPTY(a, b, c) _IF_EMPTY(GET_EMPTY(a), b, c) #define _IF_EMPTY(empty, b, c) __IF_EMPTY(empty, b, c) #define __IF_EMPTY(empty, b, c) _##c // 三层展开宏:从最外层的REMAP,到中间的STATUS,再到最内层的EVENT #define EXPAND_REMAP(R_ITEM) EXPAND_STATUS(R_ITEM, STATUS_LIST) #define EXPAND_STATUS(R_ITEM, P_ITEM) EXPAND_EVENT(R_ITEM, P_ITEM, EVENT_LIST) #define EXPAND_EVENT(R_ITEM, P_ITEM, X_ITEM) JOIN(JOIN(R_ITEM, P_ITEM), X_ITEM), // 重新定义你的宏列表,替换原来的R/P/X为展开宏 #define REMAP_LIST EXPAND_REMAP(FOE) EXPAND_REMAP(ANY) EXPAND_REMAP() #define STATUS_LIST EXPAND_STATUS(R_ITEM, TRY) EXPAND_STATUS(R_ITEM, ) EXPAND_STATUS(R_ITEM, ABORT) #define EVENT_LIST EXPAND_EVENT(R_ITEM, P_ITEM, MOVE) EXPAND_EVENT(R_ITEM, P_ITEM, HEAL) // 生成最终的枚举 enum e { REMAP_LIST // 注:C99及以后允许枚举末尾有多余逗号,主流编译器都支持 };
代码工作原理
- 空项处理:
GET_EMPTY系列宏会把空的宏参数(比如R()里的空值)转换成空字符串,这样后续拼接时不会出现FOE__MOVE这种多余的下划线。 - 逐层展开:
EXPAND_REMAP会遍历每个REMAP元素,接着调用EXPAND_STATUS遍历每个STATUS元素,最后通过EXPAND_EVENT遍历每个EVENT元素,把三者拼接成完整的枚举项。 - 标识符拼接:
JOIN宏会智能处理空参数,比如当STATUS是空的时候,会直接生成FOE_MOVE而不是FOE__MOVE。
注意事项
- 不同编译器的预处理器递归深度有限,如果你的宏列表特别长,可能需要调整编译器参数(比如GCC用
-fmax-preprocessor-depth加大深度)。 - 枚举末尾的多余逗号是C99标准允许的,GCC、Clang、MSVC等主流编译器都支持,如果你需要兼容更老的标准,可以额外加一个辅助宏来去掉最后一个逗号,但一般没必要。
备注:内容来源于stack exchange,提问作者Poeterish
相关产品推荐
相关产品推荐

