seo证书考试网站,c语言基础知识,开发什么网站,网络营销的实现方式包括【C语言进阶篇】编译和链接 #x1f955;个人主页#xff1a;开敲#x1f349; #x1f525;所属专栏#xff1a;C语言#x1f353; #x1f33c;文章目录#x1f33c;
编译环境与运行环境 1. 翻译环境 2. 编译环境#xff1a;预编译#xff08;预处理#xff09;编…【C语言进阶篇】编译和链接 个人主页开敲 所属专栏C语言 文章目录
编译环境与运行环境 1. 翻译环境 2. 编译环境预编译预处理编译汇编链接 2.1 预处理预编译 2.2 编译 2.2.1 词法分析 2.2.2 语法分析 2.2.3 语义分析 2.3 汇编 2.4 链接
3. 运行环境 编译环境与运行环境 在ANSIC的任何一种实现中存在两个不同的环境。 1. 翻译环境 那么翻译环境是怎么将源代码转换城可执行的机器指令的呢这里我们就得展开讲讲翻译环境所做的事情。 其实翻译环境是由编译和链接两个大的过程组成的而编译由可以分解成预处理预编译、编译、汇编三个过程。 一个C语言程序的项目中可能有多个.c文件一起构建那多个.c文件如何生成可执行程序呢 ① 多个.c文件单独经过编译器编译处理生成对应的目标文件。 ② 注在windows环境下的目标文件的后缀是.objLinux环境下目标文件的后缀是.o。 ③ 多个目标文件和链接库一起经过链接器处理生成最终的可执行程序。 ④ 链接库是指运行时库它是支持程序运行的基本函数集合或者第三方库。 如果再把编译器展开成3个过程那就变成了下面的过程 2. 编译环境预编译预处理编译汇编链接 2.1 预处理预编译 在预处理阶段源文件和头文件会被处理为.i为后缀的文件。 在gcc环境下想观察一下对text.c文件预处理后的.i文件命令如下 1 gcc -E test.c -o test.i 预处理阶段主要处理那些源文件中#开始的预编译指令。比如#include #define处理的规则如下 ① 将所有的#define删除并展开所有的宏定义。 ② 处理所有的条件编译指令如#if、#iddef、#elif、#else、#endif。 ③ 处理#include预编译指令将包含的头文件的内容插入到该预编译指令的位置。这个过程是递归进行的。也就是说被包含的头文件也可能包含其他头文件。注#define的包含不属于递归。 ④ 删除所有的注释这也就说明注释不是给机器看的而是给程序员看的 ⑤ 添加行号和文件名标识方便后续编译器生成调试信息等。 ⑥ 或保留所有的#pragma的编译器指令编译器后续会使用 经过预处理后的.i文件不再包含宏定义因为宏已经被展开。并且包含的头文件被插入到.i文件中。所以当我们无法知道宏定义或者头文件是否包含正确的时候可以查看预处理后的.i文件来确认。 2.2 编译 编译过程就是将预处理后的文件进行一系列的词法分析、语法分析、语义分析及优化生成相应的汇编代码如下 1 gcc -S text.i -o test.s 对下面的代码进行编译的时候会怎么做呢假设有下面代码 1 arry[index] (index4)*(26) 2.2.1 词法分析 将源代码程序被输入扫描器扫描器的任务就是简单的进行词法分析把代码中的字符分割成一系列的记号关键字、标识符、字面量、特殊字符等。 上面的程序进行词法分析后得到了16个记号 2.2.2 语法分析 然后是语法分析器将对扫描产生的记号进行语法分析从而产生语法树。这些语法树是以表达式为节点的树。 2.2.3 语义分析 由语义分析器来完成语义分析即对表达式的语法层面分析。编译器所能做的分析是语义的静态分析。静态语义分析通常包括声明和类型的匹配类型的转换等。这个阶段会报告的错误语法信息。 2.3 汇编 汇编器是将汇编代码转变成机器的可执行指令每一个汇编语句几乎都对应一条机器指令。就是根据汇编指令和机器指令的对照表一一的进行编译也不做指令优化。
汇编的命令如下 1 gcc -c test.s -o test.o 2.4 链接 ① 链接是一个复杂的过程链接的时候需要把一堆文件链接在一起才能生成可执行程序。 ② 链接过程主要包括地址和空间分配符号决议和重定位等这些步骤。 ③ 链接解决的是一个项目中多文件、多模块之间互相调用的问题。 比如
在一个C的项目中有2个.c文件text.c 和 add.c代码如下 我们知道每个源文件都是单独经过编译器处理生成对应的目标文件。 test.c经过编译器处test.o add.c经过编译器处理生成add.o 我们在test.c的文件中使用了add.c文件中的Add函数和g_val变量。 我们在test.c文件中每一次使用Add函数和g_val的时候必须确切的知道Add和g_val的地址但是由于每个文件是单独编译的在编译器test.c的时候并不知道Add函数和g_val变量的地址所以暂时把调用的Add的指令的目标地址目标地址和g_val的地址搁置。等待最后链接的时候由链接器根据引用的符号Add在其他模块中查找Add函数的地址然后将test.c中所有引用到Add的指令重新修正让他们的目标地址为真正的Add函数地址对于全局变量g_val也是类似的方法来修正地址。这个地址修正的过程也被叫做重定义。 前面我们非常简洁的讲解了一个C的程序是如何编译和链接到最终生成可执行程序的过程其实很多内部的细节无法展开讲解。比如目标文件的格式elf链接底层实现中的空间与地址分配符号解析和重定位等如果你有兴趣可以看《程序员的自我修养》——书来详细了解。
3. 运行环境 ① 程序必须载入内存中。也有操作系统的环境中一般这个由操作系统完成。在独立的环境中程序的载入必须由手工安排也可能是通过可执行代码置入只读内存来完成。 ② 程序的执行便开始。接着便调用main函数。 ③ 开始执行程序代码。这个时候程序将使用一个运行时堆栈stack存储函数的局部变量和返回地址。程序同时也可以使用静态staic内存存储于静态内存中的变量在程序的整个执行过程一直保留他们的值。 ④ 终止程序。正常终止main函数也有可能意外终止。 创作不易点个赞呗蟹蟹啦~