作者:郑沛坤
宏属于C语言中预处理命令的一种,宏的优点是:
- 方便对程序进行后期修改和裁剪;
- 提高程序的运行效率,宏可实现函数的功能,又能避免函数的入栈和出栈操作,减小系统开销;
- 宏由预处理器处理,可利用自己独特的语法实现C编译器无法实现的功能;
同时宏的缺点是:
- 宏语句晦涩难懂,影响程序的可读性;
- 由于宏语句是直接嵌入的,实现时所需的代码量会相对多一些;
- 对带参的宏而言,预处理器不会检查参数是否合法,影响程序的可靠性;
宏包含obj-like和func-like两类,其中后者可以实现类似函数的功能。
1 | //obj-like |
- 宏的语法
宏以空白符分割不同部分,空白符的多少对于宏来说是没有意义的;
1
2
3//两种表达方式效果是一样的
#define PINT int pSign
#define PINT int pSign
宏定义以换行符结尾,意味着一个宏定义中无论多长,都只能有一个换行符,如果需要分行写,需要借助\;
1
2
3
4
5#define MAIN \
int main() \
{ \
return 0; \
} \字符串化操作符#,”#”可以将参数转换为字符串进行处理;
1
2
3
4
5
6
7
8
9
if (EXP) \
{\
fprintf (stderr, "Warning: " #EXP "\n"); \
}\
//源码中
WARN_IF (x == "0")
//预处理后
if (x == "0"){fprintf (__stderrp, "Warning: " "x == \"0\"" "\n");}粘贴操作符##,”##”可以将两个参数(token)合并为一个,给用户提供了一个动态生成token的能力;
1
2
3
4
5
//源码中
GETTER(foo,const int)
//预处理后
const int get_foo() {return foo;}查看预处理器处理后的源码:
1
gcc -E test.c -o macro//test.c即源码,macro即经过预处理器后的源码
宏的嵌套
在宏的展开过程中,需要注意以下两点:
在展开过程中,如果替换列表中出现了被展开宏,那么该被展开宏将不再展开;
在每次展开过程中会创建一个”蓝色集合”,展开过的宏会放入蓝色集合中,以后的展开过程中,蓝色集合中的宏将不再继续展开;
1 |
|
Linux常用宏
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18//CONCAT宏:连接两个参数
//TYPECHECK宏:检查x是否为type类型
({ type __dummy; \
typeof(x) __dummy2; \
(void)(&__dummy == &__dummy2); \
1; \
})
//SWAP宏:交换两个变量
do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0)
//OFFSETOF宏:计算type结构体内member成员的偏移位置
//CONTAINER_OF宏:计算type结构体首地址值
const typeof(((type*)0)->member)* __mptr = (ptr); \
(type*)((char*)__mptr - offsetof(type, member)); })