Macros C:可以在粘贴之前扩展marcos,但不能递归吗?

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

我知道当存在##时,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 R_U1      2
#define U         U1
#define C(a, b)   a##b
#define R(u)      C(R_, u)
对于A
R(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
,这确实是我想知道的。谢谢你的解释!