较大的C语言项目都会用大量的宏定义来组织代码,比较经典的代码就是Linux Kernel的头文件中用的宏定义。看起来宏展开就是做个替换而已,其实里面有比较复杂的规则,有关宏展开的语法规则此小结力图整理的比较全面。
Object-like Macro
#define N 20
#define STR "hello, world"
上面源码所示的被称为Object-like Macro.
Function Macro
#define MAX(a, b) ((a)>(b)?(a):(b))
k = MAX(i&0x0f, j&0x0f)
上面源码所示的被称为Function-like Macro,注意这种函数式宏定义和真正的函数调用有什么不同:
函数式宏定义的参数没有类型,预处理器只负责做形式上的替换,而不做参数类型检查,所以传参时要格外小心。
调用真正函数的代码和调用函数式宏定义的代码编译生成的指令不同。如果MAX是个真正的函数,那么它的函数体return a > b ? a : b;要编译生成指令,代码中出现的每次调用也要编译生成传参指令和call指令。而如果MAX是个函数式宏定义,这个宏定义本身倒不必编译生成指令,但是代码中出现的每次调用编译生成的指令都相当于一个函数体,而不是简单的几条传参指令和call指令。所以,使用函数式宏定义编译生成的目标文件会比较大。
定义这种宏要格外小心,如果上面的定义写成#define MAX(a, b) (a>b?a:b),省去内层括号,则宏展开就成了k = (i&0x0f>j&0x0f?i&0x0f:j&0x0f),运算