静态链接库与动态链接库
静态链接库与动态链接库
- 一、从源程序到可执行文件
- 二、编译、链接和装入
- 三、静态链接库与动态链接库
- 四、静态链接库与动态链接库的制作与使用
- 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 库的基础知识、如何…...
docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...
label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...
UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...
Mysql8 忘记密码重置,以及问题解决
1.使用免密登录 找到配置MySQL文件,我的文件路径是/etc/mysql/my.cnf,有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...
【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...
Java详解LeetCode 热题 100(26):LeetCode 142. 环形链表 II(Linked List Cycle II)详解
文章目录 1. 题目描述1.1 链表节点定义 2. 理解题目2.1 问题可视化2.2 核心挑战 3. 解法一:HashSet 标记访问法3.1 算法思路3.2 Java代码实现3.3 详细执行过程演示3.4 执行结果示例3.5 复杂度分析3.6 优缺点分析 4. 解法二:Floyd 快慢指针法(…...
leetcode73-矩阵置零
leetcode 73 思路 记录 0 元素的位置:遍历整个矩阵,找出所有值为 0 的元素,并将它们的坐标记录在数组zeroPosition中置零操作:遍历记录的所有 0 元素位置,将每个位置对应的行和列的所有元素置为 0 具体步骤 初始化…...
使用python进行图像处理—图像滤波(5)
图像滤波是图像处理中最基本和最重要的操作之一。它的目的是在空间域上修改图像的像素值,以达到平滑(去噪)、锐化、边缘检测等效果。滤波通常通过卷积操作实现。 5.1卷积(Convolution)原理 卷积是滤波的核心。它是一种数学运算,…...
