C++程序从源代码到可执行文件的过程
概述
1. C/C++源代码从源文件到可执行文件需要经过预处理、编译、汇编、链接等4个工作过程
预处理
1. 预处理主要是对伪指令和特殊符号进行处理,将.c文件转为.i文件,具体处理如下:
(1)宏定义:如#define Name TockenString等,预编译所要作的是将程序中的全部Name全部用TockenString替换
(2)处理所有的条件编译指令,如#if、#endif、#ifdef等
(3)处理#include预编译指令,将文件内容替换到它的位置,该过程是递归进行的
(4)删除所有的注释//和/**/
(5)保留所有的#pragma编译器指令,编译器需要使用它们
(6)添加行号和文件标识,便于编译时编译器产生调试用的行号信息,该行号也是编译时产生编译错误或警告能够显示行号
编译
1. 编译阶段,主要是进行一些列词法分析、语法分析、语义分析以及优化后,生成相应的汇编代码.s文件
汇编
1. 汇编阶段是将汇编代码转变为机器可执行的指令,汇编器的汇编过程,相对简单,只是根据汇编指令和机器指令码的对照表直接翻译过程,会变完成后,可以将.s文件转为.o文件
链接
1. 链接是将多个不同的源文件进行链接,从而形成一个可执行程序
2. 链接分为静态链接和动态链接,静态链接和动态链接的最大区别就是链接的时机不一样,静态链接是在形成可执行文件之前,动态链接是在程序执行时
(1) 一个源程序是由多个源文件组成的,多个源文件之间不是相关独立的,而是存在多种依赖关系
(2)某个源文件会调用另一个源文件中的某个函数,但是每个源文件都是独立编译的,每个.c的源文件,会形成一个.o的目标文件
(3)为了满足源文件之间的依赖关系,需要将这些源文件产生的目标文件进行链接,从而形成一个可执行文件
静态链接
1. 源文件中的函数和数据预处理、编译、汇编形成目标文件,而静态链接库就是多个目标文件的集合
2. 使用静态链接库时,链接器直接从库中复制这些函数和数据,并将它们和应用程序的其他模块组合起来,创建最终的可执行文件
3. 静态链接是以目标文件为单位的,若多个函数都放在了一个目标文件中,可能很多没有的函数也会被一起链接进入了输出结果中
4. 缺点:
(1)每一个可执行文件中对所有需要的目标文件都需要一份副本,如果多个程序对同一个目标文件都有依赖,会出现同一个目标文件都在内存存在多个副本
(2)更新困难,每当库函数的代码发生改动,需要重新进行编译、连接形成可执行程序
5. 优点:
(1)可执行程序中已经具备了所有执行程序所需要的任何东西,在执行的时候运行速度更快
动态链接
1. 动态链接的基本思想是把程序按照模块拆分成各个相对独立部分,在程序运行时才将它们链接在一起形成一个完整的程序,而不是像静态链接那样运行前就把所有程序模块都链接成一个单独的可执行文件
2. 动态链接的过程:
(1)假定程序p1.o和p2.o都依赖于库lib.o,并且假定先运行p1.o,系统首先会加载p1.o,发现p1.o用到了lib.o然后将lib.o加载到内存
(2)当运行p2.o时,发现p2.o依赖于lib.o此时lib.o已经加载到内存中了,因此不需要重新加载,此时会将已经存在的lib.o映射到p2.o的虚拟地址空间中,从而进行链接,形成可执行文件
3. 优点:
(1)即使多个程序依赖于同一个库,不会像静态连接那样在内存中存在多个副本,而是多个程序在执行时共享一份副本
(2)更新方便:更新时只需要替换原来的目标文件,而无需将所有程序都重新连接一遍,当程序下次运行时,新版本的目标文件会自动被加载到内存中并连接起来,完成了程序的更新
4. 缺点:
(1)由于连接过程从编译阶段,推迟到了程序运行时,所以运行速度相对于静态链接更慢
4. 动态链接如何实现重定位的:
(1)在形成可执行文件时,发现引用了一个外部的函数,此时会检查动态链接库,发现函数名时一个动态链接符号,此时在可执行程序就不对这个符号进行重定位,就把这个过程留到装载时在进行
参考文献
1. 静态链接和动态链接
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了