一 什么是预处理
有许多文件中都内容我们是看不懂的,那怎么才能令我们看得懂呢?其实我们的系统拿到各种文件后,要进行一系列的操作过程,才能将文件转化成我们能够看得懂的信息。而翻译环境能够把源代码转换成可执行的机器指令,这个过程主要有编译和链接两个过程组成。
编译链接的过程:
预处理就是编译和链接过程中的一个阶段。在预处理阶段,源文件和头文件都会被处理成.i为后缀的文件,接下来我将详解预处理相关知识。
二 预处理指令
1 预定义符号
预定义符号:
1 __FILE__ //进⾏编译的源⽂件2 __LINE__ //⽂件当前的⾏号3 __DATE__ //⽂件被编译的⽇期4 __TIME__ //⽂件被编译的时间5 __STDC__ //如果编译器遵循ANSI C,其值为1,否则未定义注意:需要注意的是,__STDC__无法在vs中使用。
举个例子:
输出结果:
2 #define 定义常量
# define name stuff| |名字 内容
2.2 举个例⼦:
3 #define定义宏
3.1 概念:#define机制包括了⼀个规定,允许把参数替换到⽂本中,这种实现通常称为宏(macro)或定义宏(define macro)。
那我们来段代码感受一下宏/定义宏:
我们定义了一个宏ADD(a,b),又因为宏允许把参数替换到⽂本中,所以这个宏ADD(a,b)可以计算传入宏的两个参数a,b的和
3.2 宏的申明⽅式:
# define name( parament-list ) stuff其中的 parament-list 是⼀个由逗号隔开的符号表,它们可能出现在stuff中注意:参数列表的左括号必须与name紧邻,如果两者之间有任何空⽩存在,参数列表就会被解释为stuff的 ⼀部分。
3.3 使用宏/定义宏可能遇见的错误
示例:
输出结果:
从输出结果上来看,这个结果很令人出乎意料我们想得到6*7的结果,那为什么结果是13呢?这就要了解一下宏/定义宏的运行原理:其实,我们在把两个参数传过去后,(其原理是将参数在不计算的情况下直接传参传参过去)计算的其实是5+1*3+1,根据运算法则,,先算乘法再算加法,所以输出结果为13。
那怎么解决呢?我们想如果先计算a+1,在计算b+1,再计算a+1的结果*b+1的结果,这时候我们用括号把a+1括起来先计算不就可以吗?
这时候我们就得到我们想要的结果了。
4 带有副作⽤的宏参数
4.2什么是副作⽤
假如我们想令一个数+1,但是这个数自己的大小不能变:
1 x+ 1 ; //不带副作⽤ x未变2 x++;//带有副作⽤ x变大了
4.2带来的后果:当宏参数在宏的定义中出现超过⼀次的时候,如果参数带有副作⽤,那么你在使⽤这个宏的时候就可能出现危险,导致不可预测的后果。
示例:
输出结果:
我们来分析一下为什么会出现这个结果,首先我们(利用宏原理)先把宏的值全都替换掉得到:
printf("%d %d %d",a,b, ((a++) > (b++) ? (a++) : (b++)));
再分析其过程: a++的特性是先用后加,所以我们实际比较的是4和5两个数。再比较完之后,a变成5,b变成6。然后返回值为b++。同样是先用后加,所以先返回b的值6,然后再自增1,现在b等于7。
5 宏替换的规则
6 宏函数的对⽐
我们看到这应该已经能发现了,宏和函数功能及其相似,那他们两个到底谁更好呢?