继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

【学习打卡】第3天 宏函数、条件编译

慕桂英7474859
关注TA
已关注
手记 6
粉丝 4
获赞 0

课程名称: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 中 添加编译选项的方法
打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP