1 #运算符:字符串化
1.1 #运算符的基本概念
#运算符的基本概念:
- #运算符用于在预处理期将宏参数转换为字符串。
- #的转换作用是在预处理期完成的的,因此只在宏定义中有效。
- 编译器不知道#的转换作用。
用法:
#include <stdio.h>
#define A(a, b) #a#b
#define B(a) #a
int main(void)
{
A(hello, nihao);
B(Aha);
return 0;
}
预处理后的结果:
int main(void)
{
"hello""nihao";
"Aha";
return 0;
}
1.2 #运算符的妙用
#include <stdio.h>
#define CALL(f, p) (printf("Call function %s\n", #f), f(p))
int square(int n)
{
return n * n;
}
int func(int x)
{
return x;
}
int main()
{
int result = 0;
result = CALL(square, 4);
printf("result = %d\n", result);
result = CALL(func, 10);
printf("result = %d\n", result);
return 0;
}
2 ##运算符:预处理器粘合剂
2.1 ##运算符的基本概念
##运算符的基本概念:
- ##运算符用于在预处理期粘连两个标识符。
- ##的连接作用是在预处理期完成的,因此只在宏定义中有效。
- 编译器不知道##的连接作用。
用法:
//#define A(a) a //没问题,宏正常替换
//#define A(a) qa
//【大小写字母 0123456789 " ' $ _ 】--> 参数和这些字符连接,参数不替换
//#define A(a) q##a //可以正常替换
//#define A(a,b) a b //没问题
//#define A(a,b) a,b //没问题
//参数之间连接在一起,预处理器不进行参数替换
#define A(a,b) a##b
int main(void)
{
A(x,x);
return 0;
}
2.2 ##运算符的工程应用
#include <stdio.h>
#define STRUCT(type) typedef struct _tag_##type type;\
struct _tag_##type
STRUCT(Student)
{
char* name;
int id;
};
int main()
{
Student s1;
Student s2;
s1.name = "s1";
s1.id = 0;
s2.name = "s2";
s2.id = 1;
printf("s1.name = %s\n", s1.name);
printf("s1.id = %d\n", s1.id);
printf("s2.name = %s\n", s2.name);
printf("s2.id = %d\n", s2.id);
return 0;
}
3 宏不展开的特殊情况
当参数的前面有#或者##运算符时,参数不展开。
#define R B
#define A hello
#define B(x) x
#define C(x) #x
#define D(x, y) x##y
int main(void)
{
B(A);
C(A);
D(A, B);
B(R); // 宏只会替换一次,并不会进行递归替换
return 0;
}
预处理后的结果:
int main(void)
{
hello;
"A";
AB;
B;
return 0;
}