C语言编译步骤
- 预处理
- 编译
- 汇编
- 链接
什么是预处理
预处理就是在源文件(如.c文件)编译之前,所进行的一部分预备操作,这部分操作是由预处理程序自动来完成;当源文件在编译时,编译器会自动调用预处理程序来完成对预处理指令的解析,预处理指令解析完成才能进去下一步的编译过程。
我们为了能够方便的看到这个编译细节,可以使用下面命令:
gcc 源文件 -E -o 程序名[.后缀]
预处理的功能
宏定义
- 不带参数的宏定义
语法:#define 宏名 常量数据
预处理:此时的预处理只做数据替换,不做类型检查
注意:我们定义的宏是不会占用内存空间的,还没有到编译环节,就已经被替换成了我们宏中的常量数据
宏展开:在预编译时将宏名替换成字符串的过程称为“宏展开” -
案例:
#include <stdio.h> #define PI 3.1415926 void main() {float l, s, r, v;printf("input radius:");scanf("%f", &r);l = 2.0 * PI * r;s = PI * r * r;v = 4.0 / 3 * PI * r * r * r;printf("l=%10.4f\ns=%10.4f\nv=%10.4f\n", l, s, v); }
-
带参数的宏定义
-
语法:
#define 宏名(参数列表) 参数表达式
-
面试题:
#define multi(a,b)a * b
/*宏定义:带参数 */ #include <stdio.h> #define MULTI(a, b) a *b // 7 + 2 * 3int main() {int result = MULTI(7 + 2, 3);printf("%d\n", result); // 13 }
-
-
宏定义的作用域
-
#define 命令出现在程序中函数的外面,宏名的有效范围为定义命令之后到本源文件结束。通常,#define命令写在文件开头,函数之前,作为文件一部分,在此文件范围内有效。
-
可以用 #undef 命令终止宏定义的作用域
-
-
案例:
/*宏定义的作用域 */ #define PI 3.14 #define DAY 20void fun() {float r = 4;float s = PI * r * r;int day = DAY; }#undef PI // 结束PI的范围#define PI 3.1415926 void fun1() {float r1 = 4;float s1 = PI * r1 * r1;int day = DAY; }void main() {fun();fun1(); }
- 在宏定义中引用已定义的宏名
- 案例:
#include <stdio.h> #define R 3.0 #define PI 3.1415926 #define L 2 * PI *R #define S PI *R *R void main() {printf("L=%f\nS=%f\n", L, S); }
- 案例:
- 在宏定义中引用已定义的宏名
文件包含
概念
所谓“文件包含"处理是指一个源文件可以将另外一个源文件的全部内容包含进来。这个适用于多文件开发。
预处理
此时的预处理,是将文件中的内容替换,文件包含指令。
包含方式
- 第1种 : #include <xxxx.h>
- 系统会到标准库头文件目录( Linux下 /usr/include )查找包含的文件
- 第二种:#include "xxxx.h"
在当前工程路径下查找,如果未找到,仍然会到标准库头文件目录查找
- 案例:
head.h/*自定义头文件,专门用于存放被外部访问的函数的声明 */// 数组累加和计算 extern int sum(const int *p, int len);
5.c
/*实现数组元素的累加计算 */ int sum(const int *p, int len) {int sum = 0;register int i = 0;for (; i < len; i++){sum += *(p + i);}return sum; }
6.c
#include <stdio.h> // 引用自定义头文件 #include "head.h"// 如果有n多个外部函数, // 引入外部函数 // extern int sum(const int *, int);int main() {int a[5] = {12, 33, 14, 55, 34};int res = sum(a, 5);printf("数组累加结果:%d", res);return 0; }
编译命令:
gcc 5.c 6.c -o 56 //包含关系的c文件要一起编译
条件编译
概念
根据设定的条件选择待编译的语句代码。
预处理
将满足条件的语句进行保留,不满足条件的语句进行删除,交给下一步编译
语法
语法一:
#ifdef 标识 -- 判断标识符定义或未定义..
#else..
#endif
语法二:
#ifndef 标识 -- 判断标识符定义或未定义..
else..
#endif
语法三:
#if 表达式 -- 根据表达式返回的结果:0-不成立,1-成立..
#else..
#endif
案例1:
/*** 预处理-条件编译*/
#define MINUS 1
int main(void)
{
#ifndef MINUS // 判断标准是:标识有没有被定义int a = 7 - 4;
#elseint a = 7 * 4;
#endifprintf("计算结果:%d\n", a);return 0;
}
案例2:
/*预处理-条件编译:输入一行字母字符,根据需要设置条件编译,使之能将字母全改为大写输出,或全改为小写字母输出。
*/#include <stdio.h>// 定义一个标识
#define LETTER 1void main()
{// 测试用的字符数组char str[20] = "C Language";char c;int i = 0;while ((c = str[i]) != '\0'){i++;
#if LETTERif (c >= 'a' && c <= 'z'){c -= 32;}
#elseif (c >= 'A' && c <= 'Z'){c += 32;}
#endifprintf("%c", c);}printf("\n");
}
避免头文件重复包含的方法
语法:
#ifndef __XXXX_H
#define __XXXX_h...
#endif
案例:
/**
* 自定义头文件,专门用于存放被外部访问的函数的声明
*/
#ifndef __ALGORITHM_H
#define __ALGORITHM_H
// 数组的累加和计算
extern int sum(const int *p,int len);
#endif