c进阶篇(十二)——深入理解宏定义
c进阶篇(十二)——深入理解宏定义
前言:
c的语法中,最灵活的是宏使用,本篇文章将详细探讨宏的几种用法。
1 概念
在c/c++中,宏定义将一个标识符定义为一个字符串,源程序中的该标识符均以指定的字符串来替代。因此理解宏定义用法的核心是“替换”。宏定义是在预处理阶段处理的,也即在编译前就完成了宏的替换。宏的使用可以使得编程者编辑的代码得到简化,也可提高代码的运行效率。
2 规则
宏定义的语法规则如下。
1 |
宏可以带参数列表也可以不带,参数列表同样也是进行替换。处理定义处在代码中所有宏名字符串都会替换为宏体。
3 不带参宏定义
此种宏用法发简单,但却大有用处。不带参宏是没有参数列表的宏定义。
3.1 空宏用作条件编译
条件编译离不开宏,而空宏更是常用于条件编译的条件。空宏指的是没有宏体的宏定义。空宏结合带 #
的条件编译可对代码编译形成条件控制。
1 |
|
通过空宏作为条件编译条件,此时并不关心宏值,只关心宏是否被定义。通过宏的该用法加在头文件中,可以避免头文件被重复包含,放在源文件中将源文件中的代码屏蔽,避免不同源文件重复定义。
1 | //*.h文件模板。 |
3.2 常量宏方便统一修改
若一个参数在多处都被使用,当要修改该参数时需要在使用处一一修改,更好地办法是将该通用参数定义为宏,在预处理阶段自动替换。常量宏的常量可以是数值常量、字符串常量或表达式常量,现在的编译器优化会将常量表达式计算出结果。
1 |
|
以上代码多处都是用了 PI
这个数学常量,为了避免对 PI
的精度进行修改时要对所有使用处一一修改,还容易出现遗漏处,最好的办法是将这个常量定义为宏。
3.3 常量宏用作条件编译
常量宏也常与条件编译搭配,设计出不同的代码编译逻辑。
1 |
|
定义好的常量宏可以使用 #undef
重新定义其值(空宏也可重定义)。
3.4 将代码段定义为宏
直接将固定的代码段定义为宏这种用法并不常见,因为一般复用率较高的代码段都会封装为函数或宏函数,而不会直接使用一个宏名表示代码段。在c中不像对象语言是没有异常处理机制的,我见过一种用法是使用宏来实现类似c++中的 try-catch
异常处理机制,不建议这样用,在实际可以通过其他方式实现相同的效果,或者干脆用支持 try-catch
的语言好了。
1 |
3 带参宏定义
宏定义是支持带参的,但是宏的参与函数参不同,宏参也是直接替换不会进行类型检查,所以这里可能由替换引起一些“负作用”。
3.1 带返回值的宏函数
宏是直接替换,当替换的对象是常量、表达式或函数调用时宏函数可起到带返回值的效果。
1 |
1 |