课程名称:C语言系统化精讲 重塑编程思想 打造坚实的开发基础
课程章节:第五章 预处理和宏
授课老师:bennyhuo
课程内容
C宏函数
C语言中 除了简单的利用 宏代替常量以外,我们也可以利用宏编写简单的宏函数。
之所以能称之为函数,是因为其可以带入参数。
简单的例子:
#define MAX(a,b) a>b ?a :b
int max = MAX(1, 3)
但注意,这样的定义,在嵌套时,可能会出现错误,来源于替换后各种表达式的优先级不同。所以,在实际情况中,我们一般会添加一对括号,保证参数在进行运算时始终保持表达式的独立计算。
实际情况:
#define MAX(a,b) (a) > (b) ? (a) : (b)
另一个特例,如果在表达式中有自增运算,在替代后,会不经意间多计算一次:
max = MAX(max++, 5)
->
max = (max++) > 5 ? (max++) :5 // 多执行了一次
总之,在写完宏后,使用宏函数的过程要保证使用 没有副作用 的表达式。
ps:副作用是语言中的一个概念,即表达式和函数不改变变量或者状态,只返回某个值。
多行宏使用 \
连接:
#define IS_HEX_CHARACTER(ch) \
((ch) >= '0' && (ch) <= '9' ) || \
((ch) >= 'A' && (ch) <= 'F' )|| \
((ch) >= 'a' && (ch) <= 'f )
宏展开,\
并不会替换,换行符只是给编译器看的。而宏函数又因为自身没有类型的要求,所以其 可在C 中被用来方便的进行多类型的通用函数。
条件编译
在头文件中,我们常见可以见到如下宏定义:
#ifdef XXXXX_H
#define XXXXX_H
//statement
#endif
那么既然引入头文件就可以将一些函数引入,为什么要加入这些判断呢?
答案就是 :防止引入同一个头文件多次 ,因为引入同一段函数多次,在编译上一般会报错。
在多个头文件文件互相引入的时候,这可以有效避免多次引入同一段函数。
而条件编译的语句含义也非常明显:
1. #ifdef : 如果定义了
2. #ifndef : 如果没定义
3. #if 如果...
最后,他们都要和 #endif 搭配
而
有一个通用的小技巧,便是使用 defined ()
这个函数可以判断宏是否定义,通常搭配 #if
实现和ifdef
同样的作用。最终达到在不同宏,实现不同功能的作用,如:
void dump(char *message){
#ifdef DEBUG
puts(message);
#endif
}
当然你可以定义 #define DEBUG 做到调试开关的作用,更方便的做法是:
在编译时,只要了加上了宏 gcc -D DEBUG 即可
CMAKE中,如下加入定义:
target_compile_definition(${name} PUBLIC DEBUG)
有一个有意思的东西,可以判断在 C or C++ 的环境:
#ifdef __cplusplus
extern "C"{
#endif
//....
#ifdef __cplusplus
};
#endif
当然,宏编译对于跨平台编译也非常好用:
课程收获
- 理解了为什么要有条件编译
- 条件编译对 DEBUG 类的编译的作用
- 稍微熟悉了 CMAKE 中 添加编译选项的方法
共同学习,写下你的评论
评论加载中...
作者其他优质文章