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

如何用C预处理器生成X宏列表自笛卡尔积且无需重复定义列表?

问题:利用C预处理器生成X宏列表的自笛卡尔积代码

假设我们用X宏定义了如下类型列表:

#define TYPES(X, ...) \
  X(__VA_ARGS__, i, int) \
  X(__VA_ARGS__, j, unsigned int) \
  X(__VA_ARGS__, l, long) \
  X(__VA_ARGS__, m, unsigned long)

当前的做法是复制一份列表宏命名为TYPES_,再通过TYPES_(TYPES, CAST)生成所有类型对的转换函数:

#define TYPES_(X, ...) \
  X(__VA_ARGS__, i, int) \
  X(__VA_ARGS__, j, unsigned int) \
  X(__VA_ARGS__, l, long) \
  X(__VA_ARGS__, m, unsigned long)
#define CAST(FROMCH, FROMTY, TOCH, TOTY) \
  TOTY FROMCH ## to ## TOCH (FROMTY x) { return (TOTY)x; }
TYPES_(TYPES, CAST)

但直接使用TYPES会触发预处理器递归展开的限制,无法运行。我们需要一种无需重复定义列表、也不依赖特殊预处理器扩展的方法,生成列表的自笛卡尔积代码。


解决方案:拆分列表定义与调用逻辑

核心思路是把纯列表内容和X宏调用逻辑拆分开,避免递归展开的问题:

  1. 首先定义仅包含列表项的宏TYPES_LIST,这是唯一需要维护的数据源:
#define TYPES_LIST(X, ...) \
  X(__VA_ARGS__, i, int) \
  X(__VA_ARGS__, j, unsigned int) \
  X(__VA_ARGS__, l, long) \
  X(__VA_ARGS__, m, unsigned long)
  1. 原有的TYPES宏改为对TYPES_LIST的简单包装,保持原有用法兼容:
#define TYPES(X, ...) TYPES_LIST(X, __VA_ARGS__)
  1. 定义中间宏实现双层遍历:外层遍历每个源类型,内层遍历每个目标类型,生成转换函数:
// 外层遍历源类型时,调用此宏触发内层的目标类型遍历
#define GEN_CAST_FROM(FROMCH, FROMTY) TYPES_LIST(CAST, FROMCH, FROMTY)

// 单个转换函数的生成宏
#define CAST(FROMCH, FROMTY, TOCH, TOTY) \
  TOTY FROMCH ## to ## TOCH (FROMTY x) { return (TOTY)x; }

// 生成所有类型对的转换函数
TYPES(GEN_CAST_FROM)

原理说明

  • TYPES(GEN_CAST_FROM)会展开为对每个源类型(i/j/l/m)调用GEN_CAST_FROM;
  • 每个GEN_CAST_FROM(FROMCH, FROMTY)又会调用TYPES_LIST(CAST, FROMCH, FROMTY),即对每个目标类型(i/j/l/m)调用CAST宏;
  • 最终生成4×4=16个类型转换函数,完全覆盖自笛卡尔积,且全程没有递归展开问题——因为TYPES和TYPES_LIST是分离的,不会出现宏自身调用自身的情况。

这种方法仅使用标准C预处理器特性,不需要重复维护列表,后续修改类型仅需更新TYPES_LIST即可。

内容的提问来源于stack exchange,提问作者Alex Shpilkin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 18:55:19