在下面的示例中:
#define PRNT(x, y) printf("X is %s and Y is %sn", #x, #y)
int main(void)
{
PRNT("HELLO", 4);
}
这给出了:
X 是"HELLO",Y 是 4
预处理器如何在上述情况下进行替换?例如,为什么它不计算为:
- 开始:
printf("X is %s and Y is %sn", #x, #y)
- 加上 x="你好",y=4:
printf("X is %s and Y is %sn", "Hello", 4)
- Printf 应该返回:
X is Hello and Y is 4n
<--HELLO
不是"HELLO"
那么它如何/为什么围绕HELLO添加额外的"
; 也就是说,为什么它打印..."HELLO"...
而不仅仅是...HELLO...
?预处理器是否将字符串中的引号转换为"
以便在将这两个参数传递给printf
函数时最终变得"HELLO"
和"4"
?
预处理器是否将字符串中的引号转换为
"
"4"
"HELLO"
,以便在将这两个参数传递给 打印函数?
是的。
如果您愿意接受Microsoft文档,请参阅此处:
此外,如果参数中包含的字符通常需要 在字符串文本中使用时的转义序列,例如, 引号 (") 或反斜杠 (\) 字符,必要的转义 反斜杠会自动插入到字符之前。
或者,如果您更喜欢更正式的版本,以下是此 C11(草案)标准的内容:
6.10.3.2 # 运算符
。
2 语义
。 否则,参数中每个预处理标记的原始拼写 保留在字符串文本中,但用于生成 字符串文字和字符常量的拼写:在字符的每个 " 和 \ 字符之前插入一个 \ 字符 常量或字符串文字(包括分隔符), 。
对于使用"字符串化"修饰符x, y
#x, #y
,则不然。
如果你串化一个字符串,你只会得到一个字符串,但它会包含周围的引号。如果你串化一个数字,你会得到一个字符串。
一般来说,对于给定的x
你会得到"x"
,所以对于"x"
你会得到""x""
。
#X
给出一个字符串文字,其内容为 X。 因此,#
参数"FOO"
给出一个字符串文字,其五个字符分别是"
、F
、O
、O
、"
。 (当然还有空终止符)
预处理发生在代码被标记化和转义序列处理之后,预处理的结果是令牌流(不是某种需要重新标记化和重新转义处理的源文件)。
"HELLO"
是要传递到宏中的标记。#
运算符将其转换为字符串,因此您的字符串将是"\"HELLO\",就像当您将数字传入4
时,它会变成"4"
。 因此,当预处理器运行时,我希望您的代码如下所示:
int main(void)
{
printf("X is %s and Y is %sn", ""HELLO"", "4");
}
它这样做是因为宏中变量前面的"#"。它被称为"字符串化"运算符,它将接受输入变量,并对其进行字符串化。这意味着在它周围放置引号,以及转义变量中已有的引号。这意味着,当展开时,"Hello"
变得""Hello""
,4
变得"4"
。
字符串化(当您在宏中执行类似#x
的操作时会发生什么)获取项目并将其转换为字符串。在4
的情况下,你会得到"4"
,在"HELLO"
的情况下,你会得到""HELLO""
,因为这两个字符串都是你在打印项目时需要重现的确切字符串,例如。
许多编译器可以选择在预处理后停止,以允许您检查其效果,例如使用gcc
的-E
标志:
pax:~> gcc --std=c17 -E prog.c
# 1 "prog.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "prog.c"
int main(void)
{
printf("X is %s and Y is %sn", ""HELLO"", "4");
}
#x
将x
转换为字符串。
即
x = "Hello"
然后
#x = ""Hello""