目录
聪明的你一定想知道我们在平台上写的代码是究竟是如何运行呈现出来的呢,这其中就会涉及到编译和链接,详情跟着往下看吧
在标准c的任何一种实现中,都会存在两种不同的环境:
第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。
第2种是执行环境,它用于实际执行代码
1.翻译环境:
编译过程可以可划分为四个部分:
预处理阶段 -> 编译阶段 -> 汇编阶段 -> 链接
1.1预处理器
gcc编译器下预处理指令:gcc -E test.c -o test. 就会生成一个后缀为.i的目标文件,文件的内容是以下处理完后的结果
(1)、处理所有的注释,以空格代替(肉眼看相当于删除)
(2)、将所有的#define替换,展开所有的宏定义
(3)、处理条件编译指令#if,#ifdef、#elif,#else、#endif
(4)、处理#include,头的文件包含
(5)、保留编译器需要使用#pragma指令
1.2编译器
(1)、对预处理文件进行语法分析、词法分析、语义分析
语法分析:分析表达式是否遵循语法规则
词法分析:分析关键字,标识符,立即数是否合法
语义分析:在语法分析基础上进一步分析表达式是否合法
符号汇总
(2)、分析结束后进行代码优化生成相应的汇编代码文件
gcc编译器下预处理指令:gcc -S test. 就会生成一个后缀为.s的目标文件,存放的是汇编指令
1.3汇编器
(1)、汇编器将汇编代码转变为机器可以执行的指令,也就是计算机能够识别的机器指令
(2)、每条汇编指令几乎都对应一条机器指令
gcc编译器下预处理指令:gcc -c test.c 就会生成一个后缀为.o的目标文件,,存放的是二进制的信息,这种二进制通常是elf格式
1.4链接
将生成的目标文件及其所需的库文件进行链接,并解决符号引用、地址重定位等问题,确保程序能够正确地执行,生成最后的可执行程序。
(1).解决符号引用:在编译过程中,源代码文件中的函数、变量等符号可能会引用其他文件中定义的符号。链接的过程将这些符号引用与其定义进行关联,确保程序能够正确地访问到所需的符号。
(2).地址重定位:在链接过程中,目标文件中的代码和数据可能会被分配到内存的不同位置。链接器负责将这些代码和数据的地址进行重定位,确保程序能够正确地访问到它们。
(3).库文件的链接:链接器可以将程序所需的库文件与目标文件进行链接,将库文件中的函数和代码添加到最终的可执行文件中,以供程序调用和执行。
(4).优化和压缩:链接器可以对目标文件进行优化和压缩,消除冗余代码,减小可执行文件的体积,提高程序的执行效率。
2.执行环境:
程序执行的过程:
1. 程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。
2. 程序的执行便开始。接着便调用main函数。
3. 开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程一直保留他们的值。
4. 终止程序。正常终止main函数;也有可能是意外终止。
这里给大家分享一本书籍《程序员的自我修养》,里面讲解了关于编译链接的原理,有需要的小伙伴可以私聊取。为什么不推荐大家看黑皮书《编译原理》呢,因为这本书,对于计算机了解不够深入的朋友,容易劝退,简称:从入门到放弃..........
本期给大家带来的就是这些,希望对各位小伙伴有帮助,非常感谢一键三连!