C语言预处理宏是面试常考知识点,很多人只知道 #define 定义常量,却不了解两个特殊预处理运算符: # 字符串化、 ## 标记粘贴(宏参数连接)。
这两个运算符只能在宏定义内部使用, # 把宏参数转字符串; ## 用来拼接两个宏标记,也就是我们说的宏参数连接。下面结合例题,一次性讲清楚。
一、# 运算符:把宏参数变成字符串
语法: #define STR(s) #s
# 的作用:预处理阶段,将传入的宏参数,直接转换成字符串字面量。
示例代码:
c
#include <stdio.h>
#define STR(s) #s
int main()
{
printf(STR(vck));
printf("\n");
return 0;
}
预处理展开: STR(vck) → "vck"
输出结果:
plaintext
vck
重点:它不会计算表达式,只是单纯文本转字符串。 STR(1+2) 会得到字符串 "1+2" ,而不是3。
二、## 运算符:宏参数标记连接(本篇主题)
## 叫做Token-Paste,标记粘贴符,作用:将##左右两边的两个宏参数,拼接成一个新标识符/字面量,这就是宏参数连接的核心。
例题完整代码:
c
#include <stdio.h>
// #:字符串化
#define STR(s) #s
// ##:标记拼接,把a、b拼接成 aeb
#define CONS(a,b) (int)(a##e##b)
int main()
{
printf(STR(vck));
printf("\n");
printf("%d\n",CONS(2,3));
return 0;
}
展开过程
CONS(2,3) 在预处理阶段展开:
2##e##3 → 2e3
2e3 是C语言科学计数法,代表 2\times10^3=2000,强制转int,结果就是2000。
程序运行输出:
plaintext
vck
2000
三、容易踩坑的关键点
1. # 和 ## 仅存在预处理阶段,属于预处理器功能,不是C语言运行时运算。
2. ## 拼接之后,必须是合法C标记。比如变量名、数字字面量;拼接失败直接编译报错。
3. 宏只是文本替换,没有类型、没有参数计算,和函数完全不一样。
4. 不要滥用 ## ,代码可读性会下降,工程代码尽量少用。
拓展例子:用##拼接变量名
c
#include <stdio.h>
#define VAR_NAME(a,b) var##a##b
int VAR_NAME(1,2) = 100; // 预处理变成 int var12 = 100;
int main(void)
{
printf("%d", var12);
return 0;
}
这个例子可以动态拼接变量名,很多底层驱动、寄存器代码会用到。