You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用宏从常量列表生成查找表?能否省略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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 04:40:25