Loading... # 目录 1. C语言的编译过程 2. #include 3. #define 4. 条件编译 5. 二进制的概述和操作 --- ## C语言的编译过程(了解) | 序号 | 名称 | gcc操作 | | - | - | - | | 1 | 预处理 | gcc -E helloc.c -o hello.i | | 2 | 编译 | gcc -S helloc.i -o hello.s | | 3 | 汇编 | gcc -c helloc.s -o hello.o | | 4 | 链接 | gcc helloc.o -o hello_elf | <div class="tip inlineBlock warning"> 预处理:头文件包含、宏替换、条件编译、删除注释、不做语法检查。 编译:将预处理后的文件,生成汇编文件,再语法检查。 汇编:将汇编文件 编译 成二进制文件 链接:将众多的二进制文件 + 裤 + 启动代码 = 生成 可执行文件案 总结:一步到位 编译:gcc 源文件 -o 可执行文件 ![](https://blog.fivk.cn/usr/uploads/2021/03/4279669325.png) </div> ## 头文件包含 #include(了解) 文件包含处理:“文件包含处理”是指一个源文件可以将另外一个文件的全部内容包含进来。 * C语言提供了#include命令用来实现“文件包含”的操作 ![](https://blog.fivk.cn/usr/uploads/2021/03/3575856073.png) * #include<xxx.h> :表示从系统固定的目录下寻找xxx.h ![](https://blog.fivk.cn/usr/uploads/2021/03/4038184917.png) * #include "xxx.h" :表示 先从源文件 所在的目录寻找 如果找不到再从指定的目录下找 ![](https://blog.fivk.cn/usr/uploads/2021/03/2369408645.png) ## 宏定义 #define 宏定义:在源文件中,允许一个标识符(宏名)来表示一个语言符号字符窜用指定的符号代替指定的信息。 <div class='album_block'> [album type="photos"] 注意:宏名一般为大写 ### 不带参数的宏定义 > #define 宏名 字符串 > > 例:#define N 10 1. 在编译预处理时,将程序中在该语句以后出现的所有的 N 都用 10 代替 2. 这种方法使用户能以一个简单的名字代替一个长的字符串 3. 在予编译时将宏名替换成字符串的过程称为“<span style="color:#A52A2A">宏展开</span>” 4. 宏定义,只在定义的文件中起作用 ![源代码](https://blog.fivk.cn/usr/uploads/2021/03/4040837962.png) ![运行结果](https://blog.fivk.cn/usr/uploads/2021/03/315671742.png) [/album] </div> * 上图中我们把 N 替换为了 10 * 好处:便于代码的移植 > 预处理阶段开始替换内容。 ### 带参数的宏定义(宏函数) * 格式:#define 宏名(形参表) 字符串 * 调用:宏名(形参表) //类似函数调用 * 宏展开:进行宏替换 ```C #define MY_Add(a,b) a+b //调用 宏名(参数) MY_Add(10, 20);// == 10 + 20 /* 参数 a 的地方是10 则 字符串 出现a的地方就替换为 10 这就是 宏展开 */ ``` * 注意:宏的参数不能写类型 ```C //#define DEF(int a,int b) a+b //error.不能这样哦 #define DEF(a,b) a+b //这样才对 ``` * 本质:宏的本质 就是 粘贴 如图:![](https://blog.fivk.cn/usr/uploads/2021/03/893959061.png) * 那我们想让它是(10+10)*(20+20)要怎么办? <div class="tip inlineBlock success"> * 我们可以添加括号: 1. 每个字符串中的形参都加括号 2. 再在整个字符串加括号 </div> ```C #include<stdio.h> #define MY_MUL(a,b) ((a)*(b)) int main(int argc, char* argv[]) { printf("%d\n", MY_MUL(10, 20));//200 // 展开 == 10*20 printf("%d\n", MY_MUL(10 + 10, 20 + 20));//230 // 因为 a = 10+10 , b = 20+20 //所以 a*b = 10+10*20+20 //即 MY_Add(10+10, 20+20) = 10+10*20+20 //宏展开的 本质 就是粘贴 //这里在gcc 的.i文件看得很明白 return 0; } ``` ![](https://blog.fivk.cn/usr/uploads/2021/03/4131663807.png) ### 带参数的宏(宏函数) 和 普通函数有啥区别??? ```C #include<stdio.h> //宏函数 #define MY_MUL(a,b) ((a)*(b)) //普通函数 int my_mul(int a, int b) { printf("a = %d\n", a); printf("b = %d\n", b); return a * b; } int main(int argc, char* argv[]) { //宏函数 printf("%d\n", MY_MUL(10, 20));// 展开 == 10*20 printf("%d\n", MY_MUL(10 + 10, 20 + 20)); //保证完整性 // 因为 a = 10+10 , b = 20+20 //所以 a*b = ((10+10)*(20+20)) //即 MY_Add(10+10, 20+20) = ((10+10)*(20+20)) //宏展开的 本质 就是粘贴 //这里在gcc 的.i文件看得很明白 //普通函数 printf("%d\n", my_mul(10 + 10, 20 + 20)); return 0; } ``` ![运行结果](https://blog.fivk.cn/usr/uploads/2021/03/744395676.png) 区别: * **带参数的宏**:(宏函数)用多少次, 就会展开多少次,执行代码的时候实际没有函数调用的过程,也不需要函数的出入栈。 浪费空间(展开),节省了时间。 * **带参的函数**:代码只有一份,存在代码段,调用的时候去代码段读取函数指令。调用的时候,要压栈(保存调用函数前的相关信息),掉完出栈(恢复调用函数前的相关信息)。所以函数浪费了时间,节省空间。 ### 终止宏 的作用范围: #undef 宏名 ![](https://blog.fivk.cn/usr/uploads/2021/03/1954660283.png) 在第6行是识别 N 的,的9行就报错了。 ## 条件编译 #if #endif > 一般情况下源程序中所有的行都参加编译.但有时希望对部分源程序行只在满足一定条件时才编译,即对这部分源程序行指定编译条件. ![](https://blog.fivk.cn/usr/uploads/2021/03/3384151553.png) ### 案例1:测试不存在 ```C #include<stdio.h> int main(int argc, char* argv[]) { #ifndef DEF printf("----001----"); #else printf("----002----");//在预处理这一行是不存在的 #endif return 0; } ``` ![](https://blog.fivk.cn/usr/uploads/2021/03/4288082852.png) ### 案例2:测试存在 ```C #include<stdio.h> int main(int argc, char* argv[]) { #ifdef DEF printf("----001----");//在预处理这一行是不存在的 #else printf("----002----"); #endif return 0; } ``` ![](https://blog.fivk.cn/usr/uploads/2021/03/2843602745.png) ### 案例3:判断表达式 <div class='album_block'> [album type="photos"] ![条件成立](https://blog.fivk.cn/usr/uploads/2021/03/3769904215.png) ![条件不成立](https://blog.fivk.cn/usr/uploads/2021/03/4183399287.png) [/album] </div> ### 综合案例:通过条件编译 控制大小写的转换 ```C #include<stdio.h> int main(int argc, char* argv[]) { int i = 0; char buf[128] = ""; printf("请输入字符串:"); fgets(buf, sizeof(buf), stdin); //fgets 会获取 换行符 \n buf[strlen(buf) - 1] = 0; //去掉换行符 //strlen(buf)-1是换行符的位置 #if 0 //大写变小写 while (buf[i] != '\0') { if (buf[i] >= 'A' && buf[i] <= 'Z') { buf[i] += ('a' - 'A'); } i++; } #else //小写变大写 while (buf[i] != '\0') { if (buf[i] >= 'a' && buf[i] <= 'z') { buf[i] -= ('a' - 'A'); } i++; } #endif printf("%s", buf); return 0; } ``` # 作业 ```C #include<stdio.h> #define MY_Add(a,b) a+b #define MY_MUL(a,b) a*b int main(void) { printf("%d\n",MY_Add(MY_Add(10+10, 20+20),MY_MUL(10+10, 20+20))); return 0; } ``` 求输出结果. 最后修改:2021 年 03 月 19 日 © 禁止转载 打赏 赞赏作者 支付宝微信 赞 如果觉得我的文章对你有用,请随意赞赏