了解令牌粘贴
Understanding token pasting
请考虑以下代码片段,
#include<stdio.h>
#define AB "HELLO"
#define A "WORLD"
#define MAC1 A##B
void main(void)
{
printf(MAC1"\n");
}
编译执行后打印HELLO。
请帮助理解为什么 ##
在 A
和 B
之间被忽略。
同样在编译以下代码时,给出以下错误,
#include<stdio.h>
#define AB "HELLO"
#define A "WORLD"
#define MAC2 A#B
void main(void)
{
printf(MAC2"\n");
}
21.c: In function âmainâ:
21.c:11:2: error: stray â#â in program
21.c:11:9: error: expected â)â before string constant
为什么会出现这种行为?
标记#和##在宏扩展中是特殊的。 '##' 是令牌粘贴运算符。它在宏中获取 2 个符号并将它们绑定为一个符号。这对于创建专用名称很有用。
#define LINE_COUNTER static int line## __LINE__ =0; line ## __LINE__ ++;
这会创建一个变量,该变量会在该行执行时递增。它可以在同一个函数中多次使用,因为它有一个基于行号的唯一名称。 ( static int line_17 = 0; line_17 ++; )
“#”符号是字符串化运算符。它将后面的内容变成字符串。
#define assert( x ) if( ! x ) { fprintf( stderr, "Assertion failed %s\n", #x ); exit( 1 ) }
## 连接符号。换句话说,A##B 表示不存在的 AB。
如果你想做一些事情,比如从 2 个变量名中创建一个变量名,你可以这样使用:
#define newVar(x,y) x##y
int main()
{
int newVar(my,Var); // int myVar;
newVar(f,printf)(stdout,"Hello World"); // fprintf(stdout,"Hello World");
}
# 取一个名字,然后把它变成一个字符串。例如
#define VARSTR(x) #x
int main()
{
printf(VARSTR(myVar));
}
打印 "myVar" 到字符串(即使 myVar 不是 main 的变量,它在宏替换中)
#define "HELLO" "WORLD"
要连接字符串文字,只需将它们并排放置,中间没有其他有效标记。所以这导致 "HELLOWORLD" 请注意,文字之间的白色 space 被忽略,并且是不必要的。我用它来澄清它。
这将像这样替换 AA 和 BB :
#include<stdio.h>
#define AA "HELLO"
#define BB "WORLD"
#define MAC1 AA BB
void main(void)
{
printf(MAC1"\n"); // printf("HELLO" "WORLD""\n");
// same as printf("HELLOWORLD\n");
}
##
预处理令牌用于 令牌粘贴。
宏定义中 A##B
的作用是生成标记 AB
。所以 printf(MAC1"\n")
与 printf(AB"\n")
相同。
令牌不是 "ignored",它正在发挥作用。
在你的第二个例子中,A#B
只是字面上的意思 A#B
。 #
仅在类似函数的宏中具有特殊含义。所以你的代码扩展为:
printf(A#B"\n");
这是一个错误,因为 #
不是 C 语法的一部分,在预处理器之外。
正如其他人指出的那样,##
运算符用于创建新令牌。
#define MAC1 A##B
将创建定义为包含字符串 HELLO
的宏 AB
。这就是 printf(MAC1"\n")
打印 "HELLO" 的原因。如果要拼接AB
和A
表示的字符串可以定义MAC1
如下:
#define MAC1 AB A
你的预处理器将首先用 "HELLO""WORLD
替换 AB B
所以 MAC1
看起来像
#define MAC1 "HELLO""WORLD"
然后它会替换 MAC1
它出现的所有地方。所以你的 printf 语句将是
printf("HELLO""WORLD""\n"); // --> HELLOWORLD
请考虑以下代码片段,
#include<stdio.h>
#define AB "HELLO"
#define A "WORLD"
#define MAC1 A##B
void main(void)
{
printf(MAC1"\n");
}
编译执行后打印HELLO。
请帮助理解为什么 ##
在 A
和 B
之间被忽略。
同样在编译以下代码时,给出以下错误,
#include<stdio.h>
#define AB "HELLO"
#define A "WORLD"
#define MAC2 A#B
void main(void)
{
printf(MAC2"\n");
}
21.c: In function âmainâ:
21.c:11:2: error: stray â#â in program
21.c:11:9: error: expected â)â before string constant
为什么会出现这种行为?
标记#和##在宏扩展中是特殊的。 '##' 是令牌粘贴运算符。它在宏中获取 2 个符号并将它们绑定为一个符号。这对于创建专用名称很有用。
#define LINE_COUNTER static int line## __LINE__ =0; line ## __LINE__ ++;
这会创建一个变量,该变量会在该行执行时递增。它可以在同一个函数中多次使用,因为它有一个基于行号的唯一名称。 ( static int line_17 = 0; line_17 ++; )
“#”符号是字符串化运算符。它将后面的内容变成字符串。
#define assert( x ) if( ! x ) { fprintf( stderr, "Assertion failed %s\n", #x ); exit( 1 ) }
## 连接符号。换句话说,A##B 表示不存在的 AB。 如果你想做一些事情,比如从 2 个变量名中创建一个变量名,你可以这样使用:
#define newVar(x,y) x##y
int main()
{
int newVar(my,Var); // int myVar;
newVar(f,printf)(stdout,"Hello World"); // fprintf(stdout,"Hello World");
}
# 取一个名字,然后把它变成一个字符串。例如
#define VARSTR(x) #x
int main()
{
printf(VARSTR(myVar));
}
打印 "myVar" 到字符串(即使 myVar 不是 main 的变量,它在宏替换中)
#define "HELLO" "WORLD"
要连接字符串文字,只需将它们并排放置,中间没有其他有效标记。所以这导致 "HELLOWORLD" 请注意,文字之间的白色 space 被忽略,并且是不必要的。我用它来澄清它。
这将像这样替换 AA 和 BB :
#include<stdio.h>
#define AA "HELLO"
#define BB "WORLD"
#define MAC1 AA BB
void main(void)
{
printf(MAC1"\n"); // printf("HELLO" "WORLD""\n");
// same as printf("HELLOWORLD\n");
}
##
预处理令牌用于 令牌粘贴。
宏定义中 A##B
的作用是生成标记 AB
。所以 printf(MAC1"\n")
与 printf(AB"\n")
相同。
令牌不是 "ignored",它正在发挥作用。
在你的第二个例子中,A#B
只是字面上的意思 A#B
。 #
仅在类似函数的宏中具有特殊含义。所以你的代码扩展为:
printf(A#B"\n");
这是一个错误,因为 #
不是 C 语法的一部分,在预处理器之外。
正如其他人指出的那样,##
运算符用于创建新令牌。
#define MAC1 A##B
将创建定义为包含字符串 HELLO
的宏 AB
。这就是 printf(MAC1"\n")
打印 "HELLO" 的原因。如果要拼接AB
和A
表示的字符串可以定义MAC1
如下:
#define MAC1 AB A
你的预处理器将首先用 "HELLO""WORLD
替换 AB B
所以 MAC1
看起来像
#define MAC1 "HELLO""WORLD"
然后它会替换 MAC1
它出现的所有地方。所以你的 printf 语句将是
printf("HELLO""WORLD""\n"); // --> HELLOWORLD