宏相关的细节讲解。
今天继续预处理相关知识讲解。
今天也要开心哦!
宏和函数对比
宏:
- 代码长度:每次使用时,宏代码都会被插入到程序中。除了非常
小的宏之外,程序的长度会大幅度增长 - 执行速度:更快
- 操作符优先级:宏参数的求值是在所有周围表达式的上下文环境里,除非加上括号,否则邻近操作符的优先级可能会产生不可预料的后果,所以建议宏在书写的时候多些括号。
- 带有副作用的参数:参数可能被替换到宏体中的多个位置,所以带有副作
用的参数求值可能会产生不可预料的结果。 - 参数类型 :宏的参数与类型无关,只要对参数的操作是合法的,
它就可以使用于任何参数类型 - 调试 :宏不方便调试。
- 递归 :宏不能递归。
**函数 **
- 代码长度:函数代码只出现于一个地方;每次使用这个函数时,都调用那个地方的同一份代码
- 执行速度:存在函数的调用和返回的额外开销,所以相对慢一些
- 操作符优先级:函数参数只在函数调用的时候求值一次,它的结果值传递给函数。表达式的求值结果更容易预测
- 带有副作用的参数:函数参数只在传参的时候求值一次,结果更容易控制。
- 参数类型 :函数的参数是与类型有关的,如果参数的类型不同,就需要不同的函数,即使他们执行的任务是不同的。
- 调试 :函数是可以逐语句调试的
- 递归 :函数是可以递归的
函数和宏都各有优缺点,使用是分情况讨论
条件编译
单分支
#if //常量表达式
#endif//表达式由预处理求值。
看个例子:
这里可以看出,如果#if后面是0时候,可以看出打印的代码变灰色,表示不能执行这条代码。是非0则正常执行,这是条件编译一种但是必须要#if 常量表达式和#endif 联合使用才可以。
多分支:
#if 常量表达式
#elif 常量表达式
#else
#endif
看个例子:
大家可以分析下逻辑
#define NUM 3int main(){#if NUM == 1printf("胡杨\n");#elif NUM == 2printf("树下\n");#elif NUM == 3printf("胡杨树下\n");#else printf("haha\n");#endif return 0;}
这是多分支条件,最后只会执行一条语句,其他的直接在预编译时被替换了。
判断宏是否定义
有下列两种做法:
#define MAX 1int main(){#if defined(MAX)printf("1.已定义\n");#endif#ifdef MAXprintf("2.已定义\n");#endifreturn 0;}
这两种判断宏定义的办法都可以。
空内容的宏和已定义的宏区别
看个例子:
#define MAXint main(){#ifdef MAXprintf("已定义\n");#endifreturn 0;}
这里会输出已定义吗?
这是会输出的,因为定义了,只不过是空内容。
文件包含
#include “test.h”(自己创建的)
查找策略:先在源文件所在目录下查找,如果该头文件未找到,编译器就像查找库函数头文件一样在标准位置查找头文件。如果找不到就提示编译错误。
#include (库里面的)
查找头文件直接去标准路径下去查找,如果找不到就提示编译错误。
那么库中的头文件可以用 “” 引用吗?
首先是可以的,但是不推荐,但是这样做查找的效率就低些,当然这样也不容易区分是库文件还是本地文件了。
如何避免头文件重复包含的呢?
首先我们,要明白,每一次包含一个头文件,就会使程序内容大一点,会拖慢点效率,那么怎么解决呢?
1.使用条件编译。(不推荐)
在每个头文件的开头写上
#ifndef TEST_H
#define TEST_H
//头文件的内容
#endif //TEST_H
2.使用#pragma once
用#pragma once就可以避免头文件重复包含了。
下期预告:
还有一些预处理指令,
比如修改结构体默认对齐数等的没有讲,
留到下期讲解吧。下期更精彩哦~~~