C-Preprocessor-Token-Pasting-Operator

小酒小菜

Posted by Bruce Lee on 2024-05-08

c编译器名称粘结运算符(C Preprocessor Token Pasting Operator)

使用示例

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
#define concat(x, y) x ## y

int main(int argc, char** argv)
{
int concat(x, y) = 32;
printf("%d\n", concat(x, y));
return 0;
}

在工程项目中会使用到关于"##"运算符.

该运算符是由c预编译器来处理,而不是在C代码块中被处理(只能在宏中使用,不能在别的地方使用)

这个代码经过简单的gcc demo.c编译,$./a.out运行会输出:32

预编译查看源代码

在这行代码:int concat(x, y) = 32;

实际上在预编译的时候,x字母与y字母会被连接起来,生成xy(这是预编译阶段)

可以使用预编译指令:

1
gcc -E demo.c -o demo.i

生成文件的尾部:

1
2
3
4
5
6
7
# 4 "demo.c"
int main(int argc, char** argv)
{
int xy = 32;
printf("%d\n", xy);
return 0;
}

这就是预编译之后的真实c代码.没有了concat宏的使用.

错误示例

如果不在宏中使用x ## y

那么编译器会生成什么样式的报错呢?(这是经典的探索思路,探索报错样式)

编写这样的错误代码:

1
2
3
4
5
6
7
8
#include <stdio.h>
int main(int argc, char** argv)
{
int x ## y;
xy = 32;
printf("x ## y equal %d\n", xy);
return 0;
}

或者这样式的代码:

1
2
3
4
5
6
7
8
#include <stdio.h>
int main(int argc, char** argv)
{
int xy;
x ## y = 32;
printf("xy equal %d\n", xy);
return 0;
}

直接使用gcc demo1.c编译,会出现如下错误:

1
error: stray ‘##’ in program

只需要查看第一个错误就行了,后续错误很少有借鉴意义(因为大多数情况后续错误是因为第一个错误而导致的)

查看一下经过预编译之后的demo1.i文件

gcc -E demo1.c -o demo1.i

demo1.i文件最后是:

1
2
3
4
5
6
7
8
# 2 "demo1.c"
int main(int argc, char** argv)
{
int x ## y;
xy = 32;
printf("x ## y equal %d\n", xy);
return 0;
}

可以看出来预处理之后,“##“依然存在,而”##“不是严格的c标准,编译器无法直接处理”##”,所以在后续的编译成汇编阶段,会出现符号错误.

而预编译指令/运算符,需要在如#include,#define,宏中使用,不能在C标准语法代码中使用.


If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. All the images used in the blog are my original works or AI works, if you want to take it,don't hesitate. Thank you !