一.预处理指令
1.概念
C语言从源代码到可执行程序可以分为以下四个步骤(编译过程):
(1)预处理
处理源程序中的预处理指令
gcc -E xxx.c -o xxx.i
(2)编译
将预处理后的源代码编译成汇编代码
gcc -S xxx.i -o xxx.s
(3)汇编
将汇编代码汇编成目标代码(机器码)
gcc -c xxx.s -o xxx.o
(4)链接
将所有的目标代码链接成可执行程序
gcc xxx.o .... -o xxx
C源代码中以#开头的代码就叫预处理指令,预处理指令常见有以下三类
①宏定义
②条件编译
③头文件包含
2.宏定义
#define预处理指令用来定义宏
(1)宏的使用
宏名通常应该大写
宏可以用来给数字起名字,语法如下:
#define 宏名 数字
宏名和数字之间不要写"="号,宏定义语句不需要加分号
定义宏之后,可以在接下来的代码中使用宏来代替数字
宏可以在代码中来代表一个写程序时还不知道的数字,或者代表在不同版本中会改变的数字
#include <stdio.h>
#define PI 3.14 //宏定义
int main()
{
double d_num = PI;
printf("PI = %lg\n",d_num);
return 0;
}
也可以在gcc编译时使用-D定义宏
用法:
-D 宏名=数字
宏也可以给表达式起名字
#define AA 3*5
宏还可以有参数,使用这些参数来表示表达式中未知的内容
带有参数的宏叫带参宏,也叫宏函数
#define ADD(x,y) x+y //带参宏 书写不规范,表达式要加括号
#define MUL(x,y) ((x)*(y)) //带参宏
宏的参数没有数据类型
宏的预处理是使用字符替换的方式,带参宏使用二次替换的方式来处理
printf("%d\n", ADD(1,3)/*ADD(1,3)--->x+y---> 1+3*/);
定义带参宏的时候,整个表达式要用括号括起来,参数也要用括号括起来(防止优先级冲突)
(2)带参宏和函数的区别:
函数内部可以有变量而带参宏不可以
宏没有返回值,宏的处理属于整体替换
宏的参数在使用时必须加小括号函数不用
宏没有形式参数,内部直接对参数进行替换处理
宏除了通常用来给数字/表达式起名,也可以用来给一段代码起名
#define SAY_HELLO printf("hello\n")
2.条件编译
使用预处理语句从源代码文件中选择想要编译的语句,去掉不想编译的语句,这种效果就叫条件编译
(1)使用如下语句:
#ifdef/#ifndef .... #else ....(可省略) #endif
可以实现条件编译效果,根据某个宏是否被定义来决定从两组语句中选择一组编译
例:
#include <stdio.h>
#define ONE
int main()
{
//#ifdef ONE//宏被定义编译之下语句
#ifndef ONE//宏未被定义编译之下语句
printf("1\n");
#else//宏未被定义编译之下语句
printf("2\n");
#endif
return 0;
}
(2)使用如下语句:
#if .... #elif(多次) ... #else(可选) .... #endif
根据一个逻辑表达式的结果从多组语句中选择一组来编译
逻辑表达式必须能够在预处理阶段计算出结果(逻辑表达式中只能使用宏,不能用变量)
逻辑表达时钟可以使用逻辑运算符(&& || !)
//管理人员----1.2 普通白领----1.0 一般蓝领----0.8
#include <stdio.h>
//#define ELITE
#define FACTROY
int main()
{
#if defined(ELITE)
printf("120%%\n");
#elif !defined(ELITE) && !defined(FACTROY)
printf("100%%\n");
#else
printf("80%%\n");
#endif
return 0;
}
3.头文件和多文件编程
在实际开发中,一个C程序是由多个源文件编译生成的(一个程序—>多个文件---->多个函数---->多条语句)
使用gcc编译多文件程序需要在命令中加上所有.c文件的路径
gcc xxx.c yyy.c ..... -o xxx
(1)多文件程序文件内容的划分
主函数单独放在一个源文件中,源文件一般叫做main.c,里面只包含主函数
其他的函数按照功能划分在不同的文件中,一个文件中可以有多个函数
由于在调用函数和使用变量之前必须先声明,多文件编程中这个条件默认可能不满足
为了保证我们使用函数/变量前先声明,需要为每个源文件编写一个头文件(main.c除外),头文件中写对应源文件中函数和全局变量的声明
头文件以.h作为后缀,文件名和对应的源文件名相同(math.c ----- math.h),保证不同的头文件的宏名不同,避免互相冲突
头文件编写语法:
#ifndef 和头文件名相关的宏名(_MATH_H_)
#define 和头文件名相关的宏名
.....//函数和变量....的声明
#endif
注:以上语法保证只编译一次
头文件用预处理指令 #include 来包含,该预处理指令的作用将文件的内容放到当前位置,包含头文件时有以下两种语法:
#include <xxx.h> -------- 包含系统头文件
#include "xxx.h" ------- 包含自己编写的头文件
我们需要为每个源文件包含其所需要的所有头文件,源文件需要包含的头文件分为以下两类
a.配对的头文件(同名)
b.源文件中使用了头文件中声明的内容
注:在源文件中使用在另外一个源文件中声明的全局变量,需要用extern关键字再声明一次或者写入头文件