宏定义

define :-)

宏定义是C/C++系中的重要组成部分,一般在一些底层框架性代码中起着非常重要的作用,本文将以循序渐进的方式,对宏的使用进行一些总结。

基本使用

宏的基本规则

宏定义可以理解为简单地对于文本进行替换,宏的替换发生在预编译的阶段,编译器根据语义分析,将宏替换为原有的字符,这个过程称为宏的展开。也正因为宏是简单的进行文本替换,所以可能会发生许多意想不到的情况,在Effective C++中,其实作者并不建议我们滥用宏定义。

多行宏

在宏中,我们使用\进行换行,一个多行宏如下所示,最后一行不加\代表结束:

1
2
3
4
5
6
#define SYSCALL(name) \
.globl name; \
name: \
movl $SYS_ ## name, %eax; \
int $T_SYSCALL; \
ret

宏的分类

我们可以按照功能将宏进行分类,分为对象宏和函数宏两种,对象宏一般用于定义一些常数,例如:

1
#define M_PI 3.

这一句将M_PI定义为了圆周率,那么程序在预编译过程中就会将M_PI替换为魔数。

而函数宏,就是行为类似函数,可以接收参数的宏,当我们定义宏的时候在宏名字后加一对括号,就创建了函数宏:

1
2
#define MIN(A,B) A < B ? A : B
// 一个漏洞百出的函数宏

上面这个函数宏接受两个参数,返回较小的那个值.当然这个宏函数存在非常大的问题,因为宏是文本替换,而这个宏非常粗糙 ,甚至不能进行下面的计算。

1
2
3
4
int a = 2 * MIN(3, 4);
// => int a = 2 * 3 < 4 ? 3 : 4;
// => int a = 6 < 4 ? 3 : 4;
// => int a = 4; 错误结果

为何要使用宏

宏的一些高级用法

拼接

通过##可以实现对于宏的拼接过程,考虑下面这个场景,系统调用中,sys_重复出现

1
2
3
4
extern int sys_chdir(void);
extern int sys_close(void);
extern int sys_dup(void);
extern int sys_exec(void);

这种情况下,可以定义如下宏

1
2
3
4
5
6
#define SYSCALL(name) \
.globl name; \
name: \
movl $SYS_ ## name, %eax; \
int $T_SYSCALL; \
ret

当我们要用到SYS_fork时,就可以写为SYSCALL(fork),起到了精简代码的作用

参考文献

0%