目录
1.预定义符号
C语言设置了一些预定义符号,可以直接使用,预定义符号也是预处理期间处理的
2.#define定义常量
#define name stuff
#define M 100
会把M后面的100替换到M出现的位置上,并且把这句话删掉
define定义标识符的时候不建议加上 ; 这样容易出现问题
如果是if语句时,加了;时,替换的时候也会加;,此时就会有两个;,我们当然可以理解为一条空语句,但是没有大括号时if语句if后面只能跟一条语句,就出现了问题
续行符:
3.#define定义宏
宏其实是有参数的
是一个由逗号隔开的符号表,可能出现在stuff中
参数列表的左括号必须与name紧邻不能有空格,如果存在空格,参数列表就会被解释未为stuff的一部分
#define机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义宏(define macro)
宏的名字 宏的参数 宏的内容(宏的体) 宏在调用的时候最后会被替换成宏的内容
可以没有break
实现一个宏求平方
实现一个宏求一个数的两倍
实现一个宏比较大小
4.带有副作用的宏参数
当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么在使用这个宏的时候就可能会出现危险,导致不可预测的后果,副作用就是表达式求值的时候出现的永久性效果
5.宏的替换规则
1)在调用宏的时候,首先对参数进行检查,看看是否包含任何由#define定义的符号,如果是,他们首先被替换
2)替换文本随后被插入到程序中原来文本的位置,对于宏,参数名被他们的值所替换
3)最后,再次对结果文件进行扫描,看看他是否包含任何由#define定义的符号,如果是,就重复上述处理过程
宏参数和#define定义中可以出现其他#define定义的符号,但是对于宏,不能出现递归
当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索
6.宏和函数的对比
宏通常被用于执行简单的运算
在两个数中找到较大的数时,写成宏会更有优势
1.因为调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多
所以宏比函数在程序的规模和速度方面更好
2.函数的参数必须声明为特点的类型,函数只能在类型合适的表达式上使用
宏可以适用于整型,浮点型等用于>来比较,宏时无关类型的
宏的劣势
1)使用宏的时候,宏定义的代码将插入到程序中,除非宏比较短,否则可能大幅增加程序的长度
2)宏是没法调试的
3)宏是类型无关的,也就不够严谨
4)宏可能带来运算符优先级的问题,导致程序容易出错
宏的参数可以出现类型,但是函数不行
对比:
7.#和##
7.1 #运算符
#运算符将宏的一个参数转换为字符串字面量,它仅允许出现在带参数的宏的替换列表中
#运算符所执行的操作可以理解为“字符串化”
1)
7.2##运算符
##可以把位于它两边的符号合成一个符号,它允许宏定义从分离的文本片段创建标识符
##被称为记号粘合
这样的连接必须产生一个合法的标识符,否则其结果就是未定义的
8.命名约定
把宏全部大写
函数名不要全部大写
9.#undef
这条指令用于移除一个宏定义
10.命令行定义
允许在命令行中定义符号,用于启动编译过程
11.条件编译
在编译一个程序的时候我们如果要将一条语句(一组语句)编译或者放弃是很方便的,因为我们有条件编译指令
1)
2)
3)
12.头文件的包含
头文件包含的两种形式
1.#include <stdio.h> 库文件包含,一般指标准库中头文件的包含
查找头文件直接去标准路径下去查找,如果找不到就提示编译错误
2.#include "xxx.h" 本地文件包含,一般指自己创建的头文件的包含
先在源文件所在目录下查找,如果该头文件未找到,编译器就像查找库函数头文件一样在标准位置查找头文件,如果找不到就提示编译错误
对于库文件也可以使用""的形式包含?
可以,但是这样做查找的效率就低一些,当然这样也不容易区分是库文件还是本地文件了
12.2嵌套文件包含
#include指令可以使另外一个文件被编译,就像他实际出现于#include指令的地方一样
预处理器先删除这条指令,并用包含文件的内容替换
一个头文件被包含10次,那就实际被编译10次,如果重复包含,对编译的压力就比较大
如果test.h文件比较大,这样预处理后代码量会剧增,如果工程比较大,有公共使用的头文件,被
大家都能使用,又不做任何处理,那么后果不堪设想
如何解决头文件被重复引入的问题--条件编译
条件编译:满足条件参与编译
不满足就不参与编译
为真就参与编译
目录