目录
大家好,曳渔又来分享了!!
希望可以获得大家的点赞和关注!!!
一:翻译环境和编译环境:
在ANSI C的任意一种实现中,存在两种环境. 第一种环境:翻译环境:在这个环境中源代码被转换为可执行的机器指令(二进制指令)。 第二中环境:编译环境:用于实际执行代码。
1.翻译环境:
由上图可知翻译环境分为两大类组成:编译和连接。 编译又分为预处理、编译、汇编。
1).编译:
1.预处理:
主要处理源文件中以#开头指令,比如:#include #define。
规则:
·将所有的#define删除,并展开所有的宏定义
·处理所有的编译指令,比如:#if #ifdef #elif #else等
·处理#include预编译指令,将包含的有文件内容插入到该预编译指令的位置
·删除所有注释
·添加行号和文件名标识
·保留所有的#pragma的编译器指令
2.编译:
编译过程就是将预处理后的文件进行:词法分析、语法分析、语义分析及优化,生成相应的汇编代码文件
3.汇编:
将汇编代码转变成成机器可执行的命令,每一个汇编语句几乎对应着一条机械指令
2).链接:
链接是一个复杂的过程,链接的时候需要把一堆文件链接在一起才生成可执行程序
2.运行环境:
1.程序先被操作系统载入内存中。在独立的环境中,也可能是通过可执行代码置入只读内存来完成
2.程序的执行开始在调用main函数
3.开始执行程序代码,程序将使用一个运行时堆栈,存储函数的局部变量和返回地址。程序也可以同时使用静态内存,存储在静态内存中的变量在程序的整个执行过程中保留他们的值。
4.之后终止程序,正常终止main函数,也可能是意外终止程序。
二. 预处理:
1.预定义符号:
C语言中设置了一些预定义符号,也是在预处理期间处理的。
那么如何使用呢?那咱们演示一下:
2.#define符号:
1.#define定义常量:
语法:
举例:
特例 :当定义的 suff 过长的话,可以分为多行写,除了最后一行外,每行后面都加一个(\)
2.#define定义宏:
#define有一个规定,可以把参数替换到文本中。
举例:
再举一个大多数人都会错误的例子:
OK 这个代码的执行结果是什么呢?你这一看是不是以为很简单,这不就是6*6吗,不就是36吗,那你可错喽,掉坑里去了。
看吧,结果是11,不是36,这是为什么呢?直接上图片: 就是这个原因,所以执行结果是11,而非36.
那么就有人问了,那我就想是用a+1*a+1(a=5)变成36。那要怎么实现呢?上图: 看如此便实现了,使其变成36.
注意事项: 参数列表的左括号必须与name紧邻,如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分
3.带有副作用的宏参数 :
当宏参数在宏中超过一次的时候,如果参数带副作用的话,那就会有危险。
那么副作用是什么呢?就是在表达式求值的时候出现的永久性的效果。咱们直接上例子:
这就是永久性的效果,那么是怎么改变的呢?
4.宏替换的规则:
1.首先,查看是否有#define定义的参数,如果有那么先替换。
2.替换后放到程序中原来的地方,对于宏,把他们的参数名替换成他们的值
3.最后,再次查看是否还有被宏定义的符号
注意:
1.对于宏,不可以递归
2.当查找#define定义的符号是,字符串常量的内容不能查找
5.#和##的使用:
1).#——把宏参数变成对应的字符串:
注意:一定要有参数
2).##——可以将两个宏参数变成一个字符:
那么把两个函数合并成一个函数的时候怎么写呢?这时就用到了我们的##了。
这就是##的使用。
6. #undef的使用:
这就是#undef的使用了。
三.头文件的包含:
在写代码的时候我们会有两种写头文件的方法:库文件和本地文件两种。
1.头文件的包含方式:
1).库文件包含:
这种以 <> 的方式写的就是库文件包含。
查找方式:直接去标准路径下查找,如果找不到就报错。
2).本地文件包含:
这种以 "" 表示的就是本地文件包含。
查找方式:先在源文件的目录下查找,如果找不到就去标准路径下查找,如果还是没有找到就报错
2.嵌套文件包含 :
这样的头文件被编译四次的就是嵌套编译,但是过多的调用头文件,就会时编译的压力变大。
那么如何避免呢?有两种方法:
总结:
OK 喽今天的分享就到这里了,让我们下次再见啦,最后希望大家可以在我的分享中有所收获,
最最后希望可以获得大家的点赞和关注,那就再见啦~