C-Preprocessor-Token-Pasting-Operator

小酒小菜

Posted by Bruce Lee on 2024-05-08

关于我

欢迎来到我的博客!这里汇集了我对编程和技术的洞见和总结。本站内容分为几个主要类别,涵盖从具体技术实现到编程理念的广泛话题。

主要内容分类

  • 项目工程:深入探讨技术的实现细节和理解。
  • C/C++:围绕C/C++语言的技术点和编程技巧进行详细总结。
  • 程序员哲学:分享程序员在职业生涯中应该具备的哲学理念和思考方式。

想要了解更多具体内容,您可以访问文章分类页面。

联系我

如果您有任何问题或想要交流,欢迎通过关于页面与我联系。

感谢您的阅读和支持,希望我的博客能为您的技术旅程带来帮助!


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 !