在以下示例中,预处理器如何工作?



在下面的示例中:

#define PRNT(x, y) printf("X is %s and Y is %sn", #x, #y)
int main(void)
{
PRNT("HELLO", 4);
}

这给出了:

X 是"HELLO",Y 是 4

预处理器如何在上述情况下进行替换?例如,为什么它不计算为:

  1. 开始:printf("X is %s and Y is %sn", #x, #y)
  2. 加上 x="你好",y=4:printf("X is %s and Y is %sn", "Hello", 4)
  3. 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"给出一个字符串文字,其五个字符分别是"FOO"。 (当然还有空终止符)

预处理发生在代码被标记化和转义序列处理之后,预处理的结果是令牌流(不是某种需要重新标记化和重新转义处理的源文件)。

"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""

最新更新