Macros C:可以在粘贴之前扩展marcos,但不能递归吗?
我知道当存在##时,C预处理器不会扩展宏,因此需要两个级别的宏:Macros C:可以在粘贴之前扩展marcos,但不能递归吗?,macros,c-preprocessor,Macros,C Preprocessor,我知道当存在##时,C预处理器不会扩展宏,因此需要两个级别的宏: #define CAT_(a,b) a##b #define CAT(a,b) CAT_(a,b) 但这总是导致递归宏扩展 例如,如果我想将R(U)扩展到R_U1,而U是一个不幸被定义为另一个宏(用于配置)的宏,则以下两种代码都不适用于我: A #define U1 1 #define R_U1 2 #define U U1 #define R(u) R_##u B #define U1 1
#define CAT_(a,b) a##b
#define CAT(a,b) CAT_(a,b)
但这总是导致递归宏扩展
例如,如果我想将R(U)
扩展到R_U1
,而U
是一个不幸被定义为另一个宏(用于配置)的宏,则以下两种代码都不适用于我:
A
#define U1 1
#define R_U1 2
#define U U1
#define R(u) R_##u
B
#define U1 1
#define R_U1 2
#define U U1
#define C(a, b) a##b
#define R(u) C(R_, u)
对于AR(U)
展开为R\U
,这意味着宏U
未展开。对于B我得到了R_1
,它显然得到了递归扩展
那么,是否可以使用
R(U)
获得R_1
?(不限于我的一般做法。)不幸的是,不,这是不可能的(假设您的意思是询问是否可以让U
扩展到U1
,然后粘贴)
首先,我们假设我们有:
#define U1 1
#define U U1
U
…然后,此行上的U
作为类对象宏的调用,将扩展到其替换列表(U1
)。将使用涂成蓝色的U
重新扫描。重新扫描会将U1
作为类似对象的宏进行查找,并将其替换为其替换列表(1
),然后使用涂成蓝色的U1
重新扫描。结果就是1
。我们把整个序列称为扫描
因此,如果应用扫描,将得到1
。如果你没有,你只有U
我知道当##存在时,C预处理器不会展开宏,
这是真的,但对你没有帮助。假设我们将这些宏添加到:
#define CAT_(a,b) a##b
#define CAT(a,b) CAT_(a,b)
#define X x_rl
#define Y y_rl
…然后CAT(X,Y)
产生XY
,而CAT(X,Y)
产生X\u rly
。这是通过应用参数替换规则实现的。参数替换是类似函数的宏,相当于用替换列表替换类似对象的宏调用。如果某个参数出现在替换列表中,并且既没有被字符串化,也不是粘贴操作的参与者,则在替换该参数之前会扫描相应的参数。如果该参数位于替换列表中,并且正在字符串化,或者是粘贴操作的参与者,则该参数将在不进行扫描的情况下替换该参数。但同样,这意味着如果扫描适用,您将得到1
;如果没有,您将得到U
让我们将其稍微复杂一些,以便进行说明:
#define STRINGIFY(...) #__VA_ARGS__
#define PAS(X,Y) STRINGIFY(X##Y)
#define STR(X) STRINGIFY(X)
PAS(U,) // expands to "U"
STR(U) // expands to "1"
这里,STRINGIFY
被用作“塞子”;参数替换首先发生在这里,但由于这是对其参数进行字符串化,因此它们不会展开。知道这一点,PAS
在不应用扫描的情况下显示参数替换的效果STR
应用扫描时的效果STR的扩展步骤如下所示:
STR(U)
STRINGIFY(1) // U evaluated before replacing X in STR's replacement list
#1
"1"
PAS(U,)
STRINGIFY(U ## <empty-placeholder>) // U *not* evaluated before replacing X
STRINGIFY(U)
#U
"U"
PAS
的外观如下:
STR(U)
STRINGIFY(1) // U evaluated before replacing X in STR's replacement list
#1
"1"
PAS(U,)
STRINGIFY(U ## <empty-placeholder>) // U *not* evaluated before replacing X
STRINGIFY(U)
#U
"U"
PAS(U,)
STRINGIFY(U###)//U*在替换X之前未*计算
字符串化(U)
#U
“U”
这里没有“棘手的中间”解决方案。使用“粘贴”操作符延迟参数替换扫描会给您提供U
。不使用它会给您带来1
唯一的其他扫描是重新扫描和替换。在此扫描过程中,宏被“涂成蓝色”,因此它们无法再展开。但这也帮不了你。要在中间步骤中使用U1
,需要将U1
涂成蓝色。但它在扩展U1
时只会被涂成蓝色,唯一的情况是U1
被替换为1
,然后重新扫描,导致没有进一步的工作,之后U1
将被取消绘制
这三个技巧:不要计算U
,递归地计算U
,以及用蓝色颜料在某处停止某个步骤来计算U
,几乎是您可以使用的唯一工具。所有这些都不能使您的U
在任何中间步骤中变成U1
。这不是用老把戏就能解决的吗#define RR(u)R#u
#define R(u)RR(u)
@M.M我的参数是一个宏,但我只想将其展开一次,而不是递归展开。老把戏是R_1
而不是R_1
,这确实是我想知道的。谢谢你的解释!