在宏中使用#
Use of # in a macro
请解释代码
#include <stdio.h>
#define A(a,b) a##b
#define B(a) #a
#define C(a) B(a)
main()
{
printf("%s\n",C(A(1,2)));
printf("%s\n",B(A(1,2)));
}
输出
12
A(1,2)
我不明白,第一个 printf 是如何评估为 12 的?
是不是和第二个类似,C宏只是对B宏的包装?
C 预处理器有两个运算符 # 和 ##。 # 运算符将类似宏的函数的参数转换为带引号的字符串,其中 ## 运算符连接两个标识符。
#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)
类函数宏中使用了两个运算符:
##
使宏连接两个参数。
#
使输入有效地转换为字符串文字。
In 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 阅读更多相关信息。
如维基百科中所述 C-preprocessor :
The ## operator (known as the "Token Pasting Operator") concatenates
two tokens into one token.
The # operator (known as the "Stringification Operator") converts a
token into a string, escaping any quotes or backslashes appropriately.
If you want to stringify the expansion of a macro argument, you have
to use two levels of macros:
You cannot combine a macro argument with additional text and stringify
it all together. You can however write a series of adjacent string
constants and stringified arguments: the C compiler will then combine
all the adjacent string constants into one long string.
#define xstr(s) str(s)
#define str(s) #s
#define foo 4
str (foo) // outputs "foo"
xstr (foo) // outputs "4"
另外,from C-FAQ Question 11.17 :
It turns out that the definition of # says that it's supposed to
stringize a macro argument immediately, without further expanding it
(if the argument happens to be the name of another macro).
因此,类似地,沿着这些路线前进:
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) 的定义显然只完成了一级字符串化(因为它因为#而立即被字符串化)
macro-replacement of B(A(1,2))
= stringification of A(1,2)
= A(1,2).
这里的混淆来自一个简单的规则。
评估宏时,预处理器首先解析传递给宏的参数中的宏。但是,作为一种特殊情况,如果参数在 #
的右边或与 ##
相邻,它不会解析此类参数中的宏。规则就是这样。
你的第一个案例
C(A(1,2))
预处理器首先应用C(a)
宏,定义为B(a)
。定义中的参数附近没有 #
或 ##
(B(a)
中根本没有 none),因此预处理器必须解析参数中的宏:
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)"
请解释代码
#include <stdio.h>
#define A(a,b) a##b
#define B(a) #a
#define C(a) B(a)
main()
{
printf("%s\n",C(A(1,2)));
printf("%s\n",B(A(1,2)));
}
输出
12
A(1,2)
我不明白,第一个 printf 是如何评估为 12 的? 是不是和第二个类似,C宏只是对B宏的包装?
C 预处理器有两个运算符 # 和 ##。 # 运算符将类似宏的函数的参数转换为带引号的字符串,其中 ## 运算符连接两个标识符。
#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)
类函数宏中使用了两个运算符:
##
使宏连接两个参数。#
使输入有效地转换为字符串文字。
In 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 阅读更多相关信息。
如维基百科中所述 C-preprocessor :
The ## operator (known as the "Token Pasting Operator") concatenates two tokens into one token.
The # operator (known as the "Stringification Operator") converts a token into a string, escaping any quotes or backslashes appropriately.
If you want to stringify the expansion of a macro argument, you have to use two levels of macros:
You cannot combine a macro argument with additional text and stringify it all together. You can however write a series of adjacent string constants and stringified arguments: the C compiler will then combine all the adjacent string constants into one long string.
#define xstr(s) str(s)
#define str(s) #s
#define foo 4
str (foo) // outputs "foo"
xstr (foo) // outputs "4"
另外,from C-FAQ Question 11.17 :
It turns out that the definition of # says that it's supposed to stringize a macro argument immediately, without further expanding it (if the argument happens to be the name of another macro).
因此,类似地,沿着这些路线前进:
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) 的定义显然只完成了一级字符串化(因为它因为#而立即被字符串化)
macro-replacement of B(A(1,2))
= stringification of A(1,2)
= A(1,2).
这里的混淆来自一个简单的规则。
评估宏时,预处理器首先解析传递给宏的参数中的宏。但是,作为一种特殊情况,如果参数在 #
的右边或与 ##
相邻,它不会解析此类参数中的宏。规则就是这样。
你的第一个案例
C(A(1,2))
预处理器首先应用C(a)
宏,定义为B(a)
。定义中的参数附近没有 #
或 ##
(B(a)
中根本没有 none),因此预处理器必须解析参数中的宏:
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)"