静态链接库与动态链接库
静态链接库与动态链接库
- 一、从源程序到可执行文件
- 二、编译、链接和装入
- 三、静态链接库与动态链接库
- 四、静态链接库与动态链接库的制作与使用
- 1.静态库的制作及使用
- 2.动态库的制作及使用
 
一、从源程序到可执行文件
由于计算机无法直接理解和执行高级语言(C、C++、Java)程序,需要将高级语言程序转换为机器语言程序(机器语言是用二进制代码表示的、计算机唯一可以直接识别和执行的一种机器指令的集合),通常把这种转换过程叫做翻译。
在C/C++中,整个翻译过程可以分为四步:
- 预处理阶段:预处理器对源程序进行 #include头文件展开、#define宏替换、#ifdef条件编译以及行号和文件标识的添加等预处理操作,输出结果是一个以.i为扩展名的源文件。通过g++ -E main.cpp > main.i命令可以生成预处理信息并将预处理信息重定向到指定文件中。
- 编译阶段:编译器对预处理后的源程序进行词法分析、句法分析等编译操作,生成一个以.s为扩展名汇编语言源程序。汇编语言源程序中的每条语句都以一种文本格式描述了一条低级机器语言指令。通过 g++ -S main.cpp -o main.s命令即可可以编译生成汇编文件。
- 汇编阶段:汇编器将汇编语言源程序翻译成机器语言指令,并把这些指令打包成一个以.o为扩展名的可重定位目标文件,它是一种二进制文件,因此用文本编辑器打开会显示乱码。通过 g++ -c main.cpp -o main.o命令即可汇编生成可重定位目标文件。
- 链接阶段:链接器将多个可重定位目标文件和链接库合并为一个可执行目标文件,或简称可执行文件,最终生成的可执行文件被保存在磁盘上。通过 g++ main.cpp -o main命令即可实现从源程序到可执行文件的翻译过程。

二、编译、链接和装入
从操作系统程序执行的角度来看,一个程序想要放在内存中执行,除了上面的翻译过程(预处理、编译、汇编、链接),还需要对程序进行装入操作。
具体来说,编译是由编译程序对用户源程序进行编译,形成若干目标模块的过程,这些目标模块中的地址均为伪逻辑地址,即 0-10、0-10、0-10。链接则是由链接程序将一组目标模块及所需库函数进行链接,形成一个完整的装入模块的过程,这个装入模块中的地址为逻辑地址,即 0 - 32。而装入则是由装入程序将装入模块装入内存,装入后形成的是物理地址,即 1000-1032。
链接方式主要分为以下三种:
- 静态链接:装入前链接成一个完整的装入模块,以后不再拆开。
- 装入时动态链接:运行前装入内存时边装入边链接,便于对目标模块的修改、更新与共享。
- 运行时动态链接:运行时需要目标模块才装入并连接,加快了程序装入,节省了内存空间。
装入方式也有三种:
- 绝对装入:在单道程序环境下,编译时直接生成物理地址目标代码,直接按此地址装入。仅适用于单道程序,且要求程序员对内存极为熟悉,但实际上编程一般使用符号地址。
- 可重定位装入:通过静态重定位在装入时将地址变换一次性完成,一次性装入。装入时必须分配固定大小全部空间,内存不足无法装入,不支持程序浮动。
- 动态运行时装入:装入时不进行地址变换,直到运行时再借助重定位寄存器进行动态重定位。装入部分代码即可运行,可以分散存储,支持程序浮动,便于共享。
三、静态链接库与动态链接库
装入时动态链接还是运行时动态链接都属于动态链接,都是将部分链接操作推迟到程序执行时才进行,而动态链接一般需要使用动态链接库。而静态链接则是在生成可执行文件之前完成所有链接操作,使用的库文件被称作静态链接库。
静态函数库一般命名为 libxxx.a 或 xxx.lib。静态函数库在编译的时候会直接整合到目标程序中,所以利用静态函数库编译成的文件会比较大,这类函数库最大的优点就是编译成功的可执行文件可以独立运行,而不再需要向外部要求读取函数库的内容,但升级时如果函数库更新则需要重新编译。
动态函数库一般命名为 libxxx.so 或 xxx.dll。与静态函数库被整个编译到程序中不同,动态函数库只有当可执行文件需要使用到函数库的机制时,程序才会去读取函数库来使用,也就是说可执行文件无法单独运行,这样方便升级,只要替换对应动态库即可,不必重新编译整个可执行文件。
静态库和动态库最本质的区别就是加载的时机,静态库在编译阶段就会加载到可执行文件中,而动态库会在执行阶段加载到可执行文件中。
四、静态链接库与动态链接库的制作与使用
1.静态库的制作及使用
静态库的制作命令为:
g++ -c xxx.cpp -o xxx.o # 将目标源文件xxx.c编译成目标文件xxx.o
ar -rcs libxxx.a xxx.o # 使用ar工具制作静态库libxxx.a
lib_fun.h:
void func(int &num);
lib_fun.cpp:
#include "lib_fun.h"void func(int &num) {num++;
}
main.cpp:
#include <iostream>
#include "lib_fun.h"using namespace std;int main() {int x = 0;func(x);cout << x << endl;return 0;
}
首先我们使用 tree 命令查看一下当前目录结构,其中user目录模拟用户,lib目录模拟库。
atreus@iZwz9fsfltolu74amg1v0rZ:~/Code/lib_demo$ tree
.
├── lib
│   ├── lib_fun.cpp
│   └── lib_fun.h
└── user├── lib_fun.h└── main.cpp2 directories, 4 files
atreus@iZwz9fsfltolu74amg1v0rZ:~/Code/lib_demo$ 
我们在user目录下先编译一下main.cpp看一下效果,可以看到 func(int&) 声明了但没有定义,因为如果没有找到声明会直接报 was not declared in this scope。
atreus@iZwz9fsfltolu74amg1v0rZ:~/Code/lib_demo$ cd user/
atreus@iZwz9fsfltolu74amg1v0rZ:~/Code/lib_demo/user$ g++ main.cpp -o main
/usr/bin/ld: /tmp/ccnh1mTY.o: in function `main':
main.cpp:(.text+0x2a): undefined reference to `func(int&)'
collect2: error: ld returned 1 exit status
atreus@iZwz9fsfltolu74amg1v0rZ:~/Code/lib_demo/user$ 
然后我们回到lib目录制作静态库,静态库的命名格式为 libxxx.a,并将制作好的静态库拷贝到user目录下cd。
atreus@iZwz9fsfltolu74amg1v0rZ:~/Code/lib_demo/user$ cd ../lib/
atreus@iZwz9fsfltolu74amg1v0rZ:~/Code/lib_demo/lib$ g++ -c lib_fun.cpp -o lib_fun.o
atreus@iZwz9fsfltolu74amg1v0rZ:~/Code/lib_demo/lib$ ar -rcs libfun.a lib_fun.o
atreus@iZwz9fsfltolu74amg1v0rZ:~/Code/lib_demo/lib$ cp libfun.a ../user/
atreus@iZwz9fsfltolu74amg1v0rZ:~/Code/lib_demo/lib$ tree ../
../
├── lib
│   ├── libfun.a
│   ├── lib_fun.cpp
│   ├── lib_fun.h
│   └── lib_fun.o
└── user├── libfun.a├── lib_fun.h└── main.cpp2 directories, 7 files
atreus@iZwz9fsfltolu74amg1v0rZ:~/Code/lib_demo/lib$ 
我们转到user目录下,重新进行编译,编译命令中的 -l 后面跟的是动态库的名字,即 libxxx.a 中的 xxx, -L 后面跟的是静态链接库 libxxx.a 的存放位置,这里就在当前文件夹。可以看到,在链接了静态库之后就可以正常执行了。
atreus@iZwz9fsfltolu74amg1v0rZ:~/Code/lib_demo/user$ g++ main.cpp -l fun -L ./ -o main
atreus@iZwz9fsfltolu74amg1v0rZ:~/Code/lib_demo/user$ ./main 
1
atreus@iZwz9fsfltolu74amg1v0rZ:~/Code/lib_demo/user$ 
2.动态库的制作及使用
动态库的制作命令为:
g++ -shared -fPIC -o libxxx.so xxx.cpp # 制作动态库libxxx.so
首先我们依然是使用 tree 命令查看一下当前目录结构。
atreus@iZwz9fsfltolu74amg1v0rZ:~/Code/lib_demo$ tree
.
├── lib
│   ├── lib_fun.cpp
│   └── lib_fun.h
└── user├── lib_fun.h└── main.cpp2 directories, 4 files
atreus@iZwz9fsfltolu74amg1v0rZ:~/Code/lib_demo$ 
同样的,在lib目录下制作动态库,并将其拷贝到user目录下。
atreus@iZwz9fsfltolu74amg1v0rZ:~/Code/lib_demo/lib$ g++ -shared -fPIC -o libfun.so lib_fun.cpp
atreus@iZwz9fsfltolu74amg1v0rZ:~/Code/lib_demo/lib$ cp libfun.so ../user/
atreus@iZwz9fsfltolu74amg1v0rZ:~/Code/lib_demo/lib$ 
我们转到user目录下,重新进行编译,编译命令中的 ./libfun.so 即为动态库的存放路径。可以看到,在链接了动态库之后就可以正常执行了。
atreus@iZwz9fsfltolu74amg1v0rZ:~/Code/lib_demo/lib$ cd ../user/
atreus@iZwz9fsfltolu74amg1v0rZ:~/Code/lib_demo/user$ g++ main.cpp ./libfun.so -o main
atreus@iZwz9fsfltolu74amg1v0rZ:~/Code/lib_demo/user$ ./main 
1
atreus@iZwz9fsfltolu74amg1v0rZ:~/Code/lib_demo/user$ 

相关文章:
 
静态链接库与动态链接库
静态链接库与动态链接库 一、从源程序到可执行文件二、编译、链接和装入三、静态链接库与动态链接库四、静态链接库与动态链接库的制作与使用1.静态库的制作及使用2.动态库的制作及使用 一、从源程序到可执行文件 由于计算机无法直接理解和执行高级语言(C、C、Java…...
ffmpeg 抓取一帧数据
FFmpeg功能比较强大,这里记录一条从摄像机抓拍的一条命令: ffmpeg.exe -i rtsp://admin:hisense2021192.168.1.64:554/live0.264 -r 1 -ss 00:00:00 -t 00:00:01 -f image2 image.jpg ; ---执行成功。 这是一条网络摄像机的抓图命令,其实就…...
 
学好数据结构的秘诀
学好数据结构的秘诀 作为计算机专业的一名“老兵”,笔者从事数据结构和算法的研究已经近20余年了,在学习的过程中,也会遇到一些问题,但在解决问题时,积累了一些经验,为了让读者在学习数据结构的过程中少走…...
 
IT知识百科:什么是下一代防火墙和IPS?
引言 随着网络攻击的日益增多,防火墙和入侵防御系统(Intrusion Prevention System, IPS)已成为企业网络安全的必备设备。然而,传统的防火墙和IPS已经无法满足复杂多变的网络安全威胁,因此,下一代防火墙和I…...
常量指针和指针常量, top-level const和low-level const
区分常量指针和指针常量,并且认识什么是top-level const和low-level const。 1.判别: 拿到一个指针(例如const int* a),就从左往右读,只看const和*。const读作常量,*读作指针,int类型这些不用管。 2.指针常量 int a…...
 
【iOS】-- GET和POST(NSURLSession)
文章目录 NSURLSessionGET和POST区别 GET方法GET请求步骤 POSTPOST请求步骤 NSURLSessionDataDelegate代理方法AFNetWorking添加头文件GETPOST第一种第二种 NSURLSession 使用NSURLSession,一般有两步操作:通过NSURLSession的实例创建task;执…...
 
@RequestBody,@RequestParam,@RequestPart应用场景和区别
ReqeustBody 使用此注解接收参数时,适用于请求体格式为 application/json,只能用对象接收 RequestParam 支持application/json,也同样支持multipart/form-data请求 RequestPart RequestPart这个注解用在multipart/form-data表单提交请求的方法…...
 
libevent高并发网络编程 - 02_libevent缓冲IO之bufferevent
文章目录 1. 为什么需要缓冲区?2. 水位3. bufferevent常用API3.1 evconnlistener_new_bind()3.2 evconnlistener_free()3.3 bufferevent_socket_new()3.4 bufferevent_enable()3.5 bufferevent_set_timeouts()3.6 bufferevent_setcb()3.7 bufferevent_setwatermark(…...
 
院内导航移动导诊服务体系,院内导航怎么实现?
院内导航怎么实现?经过多年发展,医院规模愈加庞大,尤其是综合性医院,院区面积较大,门诊、医技、住院等大楼及楼区内部设计复杂,科室、诊室数量众多,对于新患者犹如进入了迷宫,客观环…...
MCTP协议和NCSI
MCTP(Management Component Transport Protocol)是一种管理组件传输协议,用于在计算机系统中管理各种组件,例如固件、BIOS、操作系统等。MCTP 协议定义了一种传输格式,以便在各种总线上进行通信,例如 PCIe、…...
 
Jmeter接口测试流程详解
1、jmeter简介 Jmeter是由Apache公司开发的java开源项目,所以想要使用它必须基于java环境才可以; Jmeter采用多线程,允许通过多个线程并发取样或通过独立的线程对不同的功能同时取样。 2、jmeter安装 首先需要安装jdk(最好是最…...
 
怎样使用Web自动化测试减少手动劳动?以百度网站为例
从入门到精通!企业级接口自动化测试实战,详细教学!(自学必备视频) 目录 摘要 步骤1:安装和配置Selenium 步骤2:启动浏览器并访问百度网站 步骤3:关闭浏览器 总结 摘要 本指南将…...
 
union和位域的混合使用
1、union(共用体) 1.1、概述 C 语言中,union是一种数据类型,对比于结构体,结构体中的每个成员都占用独立的内存空间,而联合中所有的成员都共享同一个内存空间。 也就是说,union中的不同成员要…...
 
PMP 高项 07-项目质量管理
项目质量管理 概念 质量的基本概念 克劳斯比:符合要求 戴明:低成本条件下可预测的一致性和可靠度,适应市场需要 朱兰:适用性,满足客户需要 国际标准化组织:质量是反映实体(产品、过程或活动等…...
 
鸿蒙Hi3861学习十一-Huawei LiteOS-M(内存池)
一、简介 LiteOS将内核与内存管理分开实现,操作系统内核仅规定了必要的内存管理函数原型,而不关心这些内存管理函数是如何实现的。 LiteOS内存管理模块管理系统的内存资源,包括:初始化、分配、释放。 不采用C标准库中的内存管理函…...
 
MySQL原理(七):内存管理和磁盘管理
前言 上一篇介绍了 MySQL 的日志,这一篇将介绍内存管理和磁盘管理相关的内容。 内存管理 MySQL 的数据都是存在磁盘中的,我们要更新一条记录的时候,得先要从磁盘读取该记录,然后在内存中修改这条记录。修改完这条记录后会缓存起…...
 
【Shell脚本】Linux安装Nginx以及开机自启
目录 一、Linux安装Nginx脚本1、把编写好的安装Nginx脚本放置到nginx.sh文件中2、在检查网络的时候,这里的IP地址,填写的需要安装Nginx服务器的IP地址3、这里的端口号可按照自己的需要进行修改4、安装Nginx脚本 二、Nginx开机自启 一、Linux安装Nginx脚本…...
 
solidworks三维建模竞赛练习题
solidworks三维建模竞赛练习题:3D01‐ 01 solidworks三维建模竞赛练习题:3D01‐ 02 solidworks三维建模竞赛练习题:3D01‐ 03 solidworks三维建模竞赛练习题:3D01‐ 04 solidworks三维建模竞赛练习题:3D01‐ 05 solidw…...
 
Redis---订阅和发布
目录 消息系统命令 消息系统  发布/订阅,即 pub/sub,是一种消息通信模式:发布者也称为消息生产者,生产和发送消息到存储系统;订阅者也称为消息消费者,从存储系统接收和消费消息。这个存储系统可以是文件系…...
 
使用Statsmodel进行假设检验和线性回归
如果你使用 Python 处理数据,你可能听说过 statsmodel 库。Statsmodels 是一个 Python 模块,它提供各种统计模型和函数来探索、分析和可视化数据。该库广泛用于学术研究、金融和数据科学。在本文中,我们将介绍 statsmodel 库的基础知识、如何…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
 
深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...
 
超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
 
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
 
无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
