理解标记粘贴 请考虑下面的代码片段, #include<stdio.h> #define AB "HELLO" #define A "WORLD" #define MAC1 A##B void main(void) { printf(MAC1"\n"); }

理解标记粘贴 请考虑下面的代码片段, #include<stdio.h> #define AB "HELLO" #define A "WORLD" #define MAC1 A##B void main(void) { printf(MAC1"\n"); },c,c-preprocessor,C,C Preprocessor,21.c:在函数–main–中: 21.c:11:2:error:trassed–in program 21.c:11:9:error:expected–before字符串常量 为什么会出现这种行为?标记#和##在宏展开中是特殊的是令牌粘贴运算符。它将宏中的2个符号绑定到一个符号中。这对于创建专用名称很有用 #define LINE_COUNTER static int line## __LINE__ =0; line ## __LINE__ ++; 这将创建一个变量,该变量在执行该行时递

21.c:在函数–main–中:
21.c:11:2:error:trassed–in program
21.c:11:9:error:expected–before字符串常量

为什么会出现这种行为?

标记#和##在宏展开中是特殊的是令牌粘贴运算符。它将宏中的2个符号绑定到一个符号中。这对于创建专用名称很有用

#define LINE_COUNTER   static int line## __LINE__ =0; line ## __LINE__ ++;
这将创建一个变量,该变量在执行该行时递增。它可以在同一函数中多次使用,因为它具有基于行号的唯一名称。(静态int line_17=0;line_17++)

“#”符号是字符串化操作符。它将其后面的内容转换为字符串

#define assert( x )  if( ! x ) { fprintf( stderr, "Assertion failed %s\n", #x ); exit(  1 ) }
##连接符号。换句话说,A##B意味着不存在的AB。 如果您想从两个变量名中生成一个变量名,可以这样使用:

#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的变量,但它在宏替换中)

要连接字符串文字,只需将它们彼此相邻放置,中间没有其他有效标记。因此,结果是“HELLOWORLD”。请注意,文本之间的空白被忽略,而且是不必要的。我用这个来澄清它

这将取代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");
}
#包括
#定义AA“你好”
#定义BB“世界”
#定义MAC1 AA BB
真空总管(真空)
{
printf(MAC1“\n”);//printf(“HELLO”“WORLD”“\n”);
//与printf相同(“HELLOWORLD\n”);
}
预处理令牌用于令牌粘贴

在宏定义中,
A##B
的作用是生成标记
AB
。因此
printf(MAC1“\n”)
printf(AB“\n”)
相同

代币没有被“忽略”,它正在发挥作用


在第二个示例中,
A#B
只是字面意思
A#B
#
仅在类似宏的函数中具有特殊意义。因此,您的代码扩展为:

printf(A#B"\n");

这是一个错误,因为
#
不是C语法的一部分,在预处理器之外。

正如其他人指出的那样,
#
操作符用于创建新的令牌。
#define MAC1 A##B
将创建宏
AB
,该宏被定义为包含字符串
HELLO
。这就是为什么
printf(MAC1“\n”)
打印“HELLO”。如果您想对由
AB
A
表示的字符串进行压缩,可以定义
MAC1
,如下所示:

#define MAC1 AB A
然后,您的预处理器将首先将
AB B
替换为
“HELLO”WORLD
,因此
MAC1
看起来是这样的

#define MAC1 "HELLO""WORLD"
然后,它将替换出现的所有位置的
MAC1
。因此,printf语句

printf("HELLO""WORLD""\n"); // --> HELLOWORLD

上面的答案不够清楚,你能以清晰的格式给出它吗?这将导致编译器错误。
#define MAC1 a##B
将创建编译器未知的符号
AB
“版本是正确的代码,但不是OP询问的内容。他没有打字错误,他想了解代码的行为。###是标记/符号连接,将其操作数转换成字符串(例如#define mac(x)#x,如果我传递mac(myVar),我会在其位置得到“myVar”。对于文字字符串连接,只需将它们彼此相邻放置(如“Hello”“World”),或者在#define MAC1 AB A)中,实际上,它将首先在宏中用“HELLO”“WORLD”替换AB A。然后,MAC1将被替换为“HELLO”“WORLD”(不是AB A first),除非我弄错了,否则它将从文件的顶部到底部读取并按顺序替换,因为AB和A是先定义的,它们将被替换为MAC1,然后是printf(MAC1…)以后得到它的替代品。这并不重要,最终都是以同样的方式发生的。
#define MAC1 "HELLO""WORLD"
printf("HELLO""WORLD""\n"); // --> HELLOWORLD