如何用宏从常量列表生成查找表?能否省略V宏包裹常量?
问题:简化常量值到名称映射表的宏定义写法
我想要创建一个从常量值映射到常量名的查找表,示例如下:
char TABLE[128][32] = { [CONST_1] = "CONST_1", [CONST_2] = "CONST_2", ... };
为此我定义了两个宏:
#define TBL(N, S, ...) static char N[S][1 << 5] = { __VA_ARGS__ }; #define V(T) [T] = #T
目前我需要这样定义查找表:
TBL (CODES, LastExtensionError, V (Success), V (BadRequest), V (BadValue), ... );
请问是否可以避免用V包裹每个常量,直接写成如下形式?
TBL (CODES, LastExtensionError, Success, BadRequest, BadValue, ...);
解决方案
可以通过C预处理器的宏展开技巧实现,核心是自动将每个传入的常量参数转换为[T] = #T的格式,无需手动包裹V宏。
方案一:递归宏(支持C20或递归宏的编译器,如GCC)
利用递归宏和C20的__VA_OPT__特性,自动遍历所有可变参数并转换:
// 单个常量的转换逻辑 #define _WRAP_CONST(c) [c] = #c // 递归展开所有参数,用逗号分隔多个转换结果 #define _WRAP_CONSTS(first, ...) _WRAP_CONST(first) \ __VA_OPT__(, ) _WRAP_CONSTS(__VA_ARGS__) // 终止递归的空宏(防止参数耗尽时报错) #define _WRAP_CONSTS() // 重定义TBL宏,自动处理所有常量参数 #define TBL(N, S, ...) static char N[S][1 << 5] = { _WRAP_CONSTS(__VA_ARGS__) };
使用示例:
TBL(CODES, LastExtensionError, Success, BadRequest, BadValue);
编译器会自动展开为:
static char CODES[LastExtensionError][32] = { [Success] = "Success", [BadRequest] = "BadRequest", [BadValue] = "BadValue" };
方案二:参数数量匹配(兼容旧版C标准)
如果编译器不支持递归宏或C20特性,可以预先定义处理不同参数数量的宏,通过参数数量匹配来自动转换:
// 单个常量的转换逻辑 #define _V(c) [c] = #c // 预定义处理不同参数数量的宏(可根据需求扩展更多数量) #define _PROCESS_1(a) _V(a) #define _PROCESS_2(a,b) _V(a), _V(b) #define _PROCESS_3(a,b,c) _V(a), _V(b), _V(c) #define _PROCESS_4(a,b,c,d) _V(a), _V(b), _V(c), _V(d) // 根据传入参数的数量,选择对应的处理宏 #define _GET_PROCESSOR(_1,_2,_3,_4,NAME,...) NAME #define PROCESS_CONSTS(...) _GET_PROCESSOR(__VA_ARGS__, _PROCESS_4, _PROCESS_3, _PROCESS_2, _PROCESS_1)(__VA_ARGS__) // 重定义TBL宏 #define TBL(N, S, ...) static char N[S][1 << 5] = { PROCESS_CONSTS(__VA_ARGS__) };
这种方式的局限性是需要提前覆盖可能用到的参数数量上限,但对于常量数量固定的场景足够实用。
内容的提问来源于stack exchange,提问作者andreoss
相关产品推荐
相关产品推荐

