预处理指令分类
- 文件包含指令
- 宏定义:可以定义一段C代码为一个标识,使用这个标识就可以使用这段代码
- 条件编译指令:只编译符合条件的C代码为二进制指令
预处理指令的特点
- 都是以#号开头
- 预处理指令都是在编译之前执行
- 预处理指令后面没有分号
C语言编写->编译->链接->执行的过程
- 创建.c的源文件(源文件)
- 在.c源文件编写符合c语言语法的代码,C语言严格区分大小写,除了字符串常量,其他的地方必须使用英文输入法。
- 使用cc -c 编译源文件
1)执行源文件中预处理指令,如果有文件包含内容拷贝到写指令的位置
2)检查.c文件语法是否符合规范
如果符合:生成.o目标文件,就是源文件对应的二进制指令
如果不符合:编译器报错 - 链接
1)为目标文件添加启动代码
2)链接函数,告知编译器调用的函数在什么地方
3)链接成功,生成一个可执行文件。这个文件就是可执行文件
宏定义指令
语法:
#define 宏名 宏值
#define N 10;
原理
在预编译的时候,会执行源文件中预处理指令,在C代码中会将使用宏名的地方替换为宏值。这个替换的过程称为宏替换或者叫宏代换。
使用宏需要注意的地方
- 宏值可以是任意的值,瞎写也没有问题。
- 在定义宏的时候并不会检查语法,在宏替换的时候回去检查语法规范。
- 如果宏值是个表达式,宏值并不是表达式的结果,而是表达式的本身。
- 如果在宏值中使用变量名,那么在使用这个宏之前,需保证使用的变量名已经声明。
- 无法通过赋值运算符为宏赋值
- 宏的作用域,宏可以定义在函数的内部和函数的外部。从定义宏的地方开始,后面都可以使用改宏。直到结束改宏指令(#undef 宏名)undef 指令可以提前结束宏定义指令。
- 字符串当中,如果出现宏名,系统不会认为是宏名,而会认为该宏名是字符串的一部分,所以不回进行宏替换
- 宏的层层替换,指在宏值当中使用另外的宏名。
- 如果宏值后面跟分号,那么替换的使用会将分号作用宏值的一部分一起替换
- 可以将任意的C代码定义为宏。
define和typedef区别
- define在预编译的时候执行,typedef是C语言的代码,运行的时候才会执行
- define可以任意的C代码取一个标识名,typedef只能为数据类型取名字。
带参数宏定义指令
#define 宏名(参数) 宏值
#define N(a) a+10;
如果使用这个有参数的宏,那么就必须在使用它的使用为它的参数传值。
带参数宏执行过程
- 现将传入的值传递给宏值。
- 再把宏值当中使用参数的地方替换为参数的值。
- 再将使用宏名的地方,替换为最后的宏值。
使用带参数宏注意
- 宏名不是函数,所以不需要写参数定义,直接写参数名即可
- 宏名和宏值是用空格隔开的
- 宏参数传递时候,传递的并不是值,而是传递本色。因为程序还没有运行变量的值是不知道的。
- 宏定义只能写在同一行,换行宏定义就结束了
条件编译指令
它是预处理指令,只编译符合条件的C代码为二进制指令
语法:
#if 条件
c代码
#endif
#if 条件
c代码
#elif 条件
c代码
#else 条件
c代码
#endif
#ifdef 宏名 //如果宏被定义,就编译c代码
c代码
#endif
#ifndef 宏名 //如果宏没有定义,就编译c代码
c代码
#endif
如果条件成立,会将c代码编译成二进制指令,如果条件不成立就不回编译条件编译指令c代码。
条件只能是宏,不能是变量。