这个问题在这里已有答案:
起源
答案:
这里的困惑来自一个简单的规则。
在评估宏时,预处理器首先解析传递给宏的参数中的宏。但是,作为一个特例,如果一个论证是正确的 #
或毗邻 ##
,它不解析这些参数中的宏。这是规则。
你的第一个案子
C(A(1,2))
预处理器首先应用 C(a)
宏,定义为 B(a)
。没有 #
要么 ##
与定义中的参数相邻(其中没有一个在 B(a)
所有),因此预处理器必须解析参数中的宏:
A(1,2)
的定义 A(a,b)
是 a##b
评估为 12
。
在参数中的宏之后 C(a)
宏被评估,C宏变为:
C(12)
预处理器现在解决了 C(a)
宏,根据其定义成为
B(12)
完成此操作后,预处理器将再次评估结果中的宏并应用 B(a)
宏,所以结果变成了
"12"
你的第二个案子
B(A(1,2))
与第一种情况类似,预处理器首先应用 B(a)
宏。但是这一次,宏的定义是这样的,前面的参数是 #
。因此,特殊规则适用于参数内的宏 不 评估。因此,结果立即变为:
"A(1,2)"
预处理器再次检查结果,试图找到更多要扩展的宏,但现在一切都是字符串的一部分,并且宏不会在字符串中扩展。所以最终的结果是:
"A(1,2)"
如维基百科中所述 C预 :
##运算符(称为“令牌粘贴运算符”)连接在一起 两个令牌成一个令牌。
#运算符(称为“字符串化运算符”)转换a 令牌成为字符串,适当地转义任何引号或反斜杠。
如果要对宏参数的扩展进行字符串化,则可以 使用两个级别的宏:
您不能将宏参数与其他文本和stringify组合在一起 这一切都在一起。但是,您可以编写一系列相邻的字符串 常量和字符串化参数:然后C编译器将合并 所有相邻的字符串常量为一个长字符串。
#define xstr(s) str(s)
#define str(s) #s
#define foo 4
str (foo) // outputs "foo"
xstr (foo) // outputs "4"
也, 来自C-FAQ问题11.17 :
事实证明#的定义说它应该是 立即对一个宏参数进行字符串化,而不进一步扩展它 (如果参数恰好是另一个宏的名称)。
所以,同样地,沿着这些方向:
you're doing C(A(1,2)),
which would roll to C(12), // since no #, so inner argument is expanded
and then to B(12)
// [since you've done two levels of macros in the code:
// 1. from C() to B(), and then, 2. B() to #a]
= 12 .
然而,在第一种情况下,根据B(a)的定义,只明确地完成了1级字符串化(因为它因#而立即被字符串化)
macro-replacement of B(A(1,2))
= stringification of A(1,2)
= A(1,2).
C预处理器有两个运算符#和##。 #运算符将像macro这样的函数的参数转换为带引号的字符串,其中##运算符连接两个标识符。
#define A(a,b) a##b will concatenate a with b returning ab as string.
so A(1,2) will return 12
#define B(a) #a will return a as string
#define C(a) B(a) will call previous one and return a as string.
so C(A(1,2)) = C(12) = B(12) = 12 (as string)
B(A(1,2)) = A(1,2) because A(1,2) is taken as an argument and returned as string A(1,2)
函数式宏中使用了两个运算符:
##
导致宏连接两个参数。#
导致输入有效地转换为字符串文字。
在 A(a,b)
##
导致a与b连接。在 B(a)
, #
从输入中有效地创建一个字符串文字。因此扩展运行如下:
C(A(1,2)) -> C(12) -> B(12) -> "12"
B(A(1,2)) -> "A(1,2)"
因为 C(A(1,2))
, A(1,2)
首先评估部分变成12,这两个陈述不像他们看起来那样相等。
你可以在这里阅读更多相关信息 cppreference。