Unity中HLSL/Cg预处理器表现异常?宏展开不符预期问询
HLSL/Cg预处理器与标准C预处理器的宏展开差异问题
嘿,这个宏展开的坑我之前踩过!你遇到的问题本质是HLSL/Cg预处理器在宏连接(##操作符)的处理顺序上,和标准C预处理器存在关键差异,咱们一步步拆解分析:
首先先把你的宏代码贴出来方便对照:
#define read(name) read2(TYPEOF(name), name) #define TYPEOF(name) typeof_ ## name #define read2(t, name) TYPEOF_READ(t, name) #define TYPEOF_READ(a, b) a ## _read(b) #define typeof_X float read(X);
先看标准C预处理器的预期展开流程
标准C会遵循「先展开参数,再执行连接」的规则:
read(X)替换为read2(TYPEOF(X), X)- 先展开
TYPEOF(X):typeof_##X→typeof_X,接着typeof_X被替换为float,于是变成read2(float, X) read2(float, X)替换为TYPEOF_READ(float, X)- 最后
TYPEOF_READ(float, X)执行连接:float##_read(X)→float_read(X),完全符合你的预期。
但HLSL/Cg预处理器的处理逻辑不一样!
HLSL/Cg的预处理器对带##的宏,会先执行连接操作,再尝试展开参数,这就导致了你的报错:
read(X)→read2(TYPEOF(X), X)read2(TYPEOF(X), X)→TYPEOF_READ(TYPEOF(X), X)- 重点来了:
TYPEOF_READ(a, b)里的a##_read会先把TYPEOF(X)和_read直接连接,得到typeof_X_read,而不是先展开TYPEOF(X)为float - 此时预处理器去找
typeof_X_read的定义,但你只定义了typeof_X,自然就报「未声明的标识符typeof_X_read」了!
解决方法:加一层中间宏延迟连接
要让参数先完全展开再执行连接,只需要新增一个中间宏来延迟连接操作,修改后的宏代码如下:
// 新增中间宏:先展开参数,再执行连接 #define CONCAT(a, b) a ## b #define TYPEOF_READ(a, b) CONCAT(a, _read)(b) #define read(name) read2(TYPEOF(name), name) #define TYPEOF(name) typeof_ ## name #define read2(t, name) TYPEOF_READ(t, name) #define typeof_X float read(X); // 现在会正确展开为 float_read(X)
原理是:当TYPEOF_READ调用CONCAT(a, _read)时,参数a(也就是TYPEOF(X))会先被完全展开成float,再和_read连接得到float_read,最终生成正确的float_read(X)。
核心差异总结
- 标准C预处理器:处理带
##的宏时,会先完全展开所有参数(除非参数包含#或##),再执行连接操作。 - HLSL/Cg预处理器:处理带
##的宏时,优先执行连接操作,再尝试展开连接后的结果,嵌套的带##的宏参数不会被提前展开。
内容的提问来源于stack exchange,提问作者darkspider
相关产品推荐
相关产品推荐

