• 【c语言】编译链接--详解


    一.程序的翻译环境和运行环境

    ANSI C的任何⼀种实现中,存在两个不同的环境。
    第1种是翻译环境,在这个环境中源代码被转换为可执⾏的机器指令
    第2种是执行环境,它⽤于实际执⾏代码

    在这里插入图片描述

    二.翻译环境:预编译+编译+汇编+链接

    翻译环境
    在这里插入图片描述
    一个程序可能不止一个.c文件
    • 多个.c⽂件单独经过编译出编译处理⽣产对应的目标文件
    • 多个⽬标⽂件和链接库⼀起经过链接器处理⽣成最终的可执⾏程序。
    • 链接库是指运⾏时库(它是⽀持程序运⾏的基本函数集合)或者第三⽅库。

    编译过程可以分为预处理编译汇编三个阶段。
    在这里插入图片描述

    (一)预编译

    1.将所有的#define删除,展开所有的宏定义

    //预处理前
    #define M 5
    int main()
    {
    	int a = M;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    //预处理后
    int main()
    {
    int a=5;
    return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.处理所有的条件编译指令,如:#if、#ifdef、#elif、#else、#endif 。
    3.处理#include 预编译指令,将包含的头⽂件的内容插⼊到该预编译指令的位置。这个过程是递归进⾏的,也就是说被包含的头⽂件也可能包含其他⽂件。

    #include
    //将头文件插入到目标文件中
    
    • 1
    • 2

    4.删除所有的注释,以减小目标文件的大小。
    5.添加行号和文件名标识,⽅便后续编译器⽣成调试信息等。
    6.或保留所有的#pragma的编译器指令,编译器后续会使⽤。

    (二)编译

    把c语言代码翻译成汇编代码

    编译过程就是将预处理后的⽂件进⾏⼀系列的:词法分析语法分析语义分析及优化,⽣成相应的汇编代码⽂件。
    对下⾯代码进⾏编译的时候,会怎么做呢?假设有下⾯的代码

    array[index] = (index+4)*(2+6);
    
    • 1

    1)词法分析

    将代码分割成一系列的记号,例如**(关键字、标识符、字⾯量、特殊字符等)**

    在这里插入图片描述

    2)语法分析

    接下来语法分析器,将对扫描产⽣的记号进⾏语法分析,从⽽产⽣语法树。这些语法树是以表达式为节点的树。

    在这里插入图片描述

    3)语义分析

    语义分析器来完成语义分析,编译器所能做的分析是语义的静态分析。通常包括声明和类型的匹配,类型的转换等。这个阶段会报告错误的语法信息

    在这里插入图片描述
    4)符号汇总
    在后面链接部分会讲到
    汇总的符号一般是全局的符号

    (三)汇编

    把汇编代码翻译成了二进制的指令生产了.o文件(目标文件),生成符号表

    汇编器是将汇编代码转转变成机器可执⾏的指令,每⼀个汇编语句⼏乎都对应⼀条机器指令。就是根
    据汇编指令和机器指令的对照表⼀⼀的进⾏翻译,也不做指令优化

    (四)链接

    链接目标文件和链接库生成可执行程序二进制程序
    1.符号表的汇总
    2.符号表的合并和重定义

    1.编译过程中进行符号汇总

    前面我们说到在编译过程中会进行符号汇总。
    在如下add.c文件中,汇总到一个 Add符号
    ![在这里插入图片描述](https://img-blog.csdnimg.cn/ed55807131dc482dbc8a295c5b2dfd85.png
    在test.c文件中,汇总到 Add和main
    在这里插入图片描述

    2.汇编过程中生成符号表

    在这里插入图片描述
    在这里插入图片描述

    3.链接符号表汇总

    在这里插入图片描述

    运行环境

    1. 程序必须载⼊内存中。在有操作系统的环境中:⼀般这个由操作系统完成。在独⽴的环境中,程序的载⼊必须由⼿⼯安排,也可能是通过可执⾏代码置⼊只读内存来完成。
    2. 程序的执⾏便开始。接着便调⽤main函数。
    3. 开始执⾏程序代码。这个时候程序将使⽤⼀个运⾏时堆栈(stack),存储函数的局部变量和返回地址。程序同时也可以使⽤静态(static)内存,存储于静态内存中的变量在程序的整个执⾏过程⼀直保留他们的值。
    4. 终⽌程序。正常终⽌main函数;也有可能是意外终⽌。

    码字不易,感谢观看。

    如果对你有帮助的话,记得点赞👍+评论+关注哦

  • 相关阅读:
    利用EFK对日志进行采集
    DXF笔记:线型CENTER的格式及绘制思想
    优思学院|现代质量管理实践与六西格玛方法论如何融合?
    23年底,我出齐了Spring boot,Spring cloud和案例方面的书,正在写一本面试书(代年终总结)
    【luogu CF1609G】A Stroll Around the Matrix(贪心)(线段树)
    深度解析linux内核模块编译makefile
    请问WPF的LiveCharts怎么解决这种X轴Labels自动跟随数据点的情况
    python迭代器模块itertools常用方法
    react中受控组件与非受控组件
    接口--抽象方法
  • 原文地址:https://blog.csdn.net/2202_75795446/article/details/133890198