MSVC预处理器展开宏时忽略令牌的触发条件与规则
传统MSVC预处理器宏展开令牌擦除行为规则问询
研究背景
- 此前查阅Stack Overflow上题为Macro expansion ignores some tokens in MSVC的问题后,我对MSVC预处理器的特殊行为产生了研究兴趣。目前行业内遇到这类宏展开异常问题,通用建议都是放弃使用传统MSVC预处理器,切换到符合C/C++标准的新版预处理器,但出于技术研究目的,我希望彻底理清传统MSVC预处理器宏展开的具体执行逻辑。
- 我在Godbolt平台做了一系列预处理器行为测试,最初提出猜想:如果MSVC在处理某个函数式宏的参数列表时,识别到参数内部存在其他函数式宏,且判定不对这个内部宏做展开,就会把对应参数列表直接替换成这个未展开的函数式宏的名称。
- 这个猜想在单参数宏场景下吻合度很高,和平台上的单参数测试结果完全匹配,但没法解释双参数宏的展开结果,双参数宏的展开逻辑显然还有其他规则。
测试代码与不同预处理器结果对比
测试用宏定义与传统MSVC展开结果
测试所用代码及传统MSVC预处理器的实际展开结果如下:
#define S(s) s #define Z(a, b) a b #define F() #define K() S(x S(F) x) #define L() S(x S(F)) #define M() S(S(F) x) #define N2() S(F) x #define N() S(N2()) #define O() S(S(S) x) #define P() S(S(A) x) #define R() Z(Z(F,F) x, Z(Z,Z) y) #define Q() Z(Z(Z,Z) x, Z(F,F) y) K() // 展开结果: 'F' L() // 展开结果: 'x F' M() // 展开结果: 'F' N() // 展开结果: 'F x' O() // 展开结果: 'S x' P() // 展开结果: 'A x' R() // 展开结果: 'F F' Q() // 展开结果: 'Z Z x F'
GCC预处理器展开结果
相同代码在遵循C/C++标准实现的GCC预处理器下,输出和MSVC差异明显,具体输出如下:
x F x x F F x F x S x A x F F x Z Z y Z Z x F F y
核心问询
我查阅了MSVC预处理器的官方公开文档,没有找到对上述令牌擦除行为的相关说明,现提出两个明确问题:
- MSVC预处理器擦除参数列表内部分令牌的行为,具体触发场景是什么?
- 被擦除的令牌具体包含哪些类型?
说明:本问题不是为了反馈MSVC预处理器的行为不符合预期,核心目的是明确MSVC传统预处理器和GCC预处理器的行为差异,梳理传统MSVC预处理器实际执行的宏展开规则。
内容的提问来源于stack exchange,提问作者CoffeeTableEspresso
相关产品推荐
相关产品推荐

