静态链接库与动态链接库
静态链接库与动态链接库
- 一、从源程序到可执行文件
- 二、编译、链接和装入
- 三、静态链接库与动态链接库
- 四、静态链接库与动态链接库的制作与使用
- 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 库的基础知识、如何…...
工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...
dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...
在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)
考察一般的三次多项式,以r为参数: p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]; 此多项式的根为: 尽管看起来这个多项式是特殊的,其实一般的三次多项式都是可以通过线性变换化为这个形式…...
Bean 作用域有哪些?如何答出技术深度?
导语: Spring 面试绕不开 Bean 的作用域问题,这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开,结合典型面试题及实战场景,帮你厘清重点,打破模板式回答,…...
stm32wle5 lpuart DMA数据不接收
配置波特率9600时,需要使用外部低速晶振...
基于开源AI智能名片链动2 + 1模式S2B2C商城小程序的沉浸式体验营销研究
摘要:在消费市场竞争日益激烈的当下,传统体验营销方式存在诸多局限。本文聚焦开源AI智能名片链动2 1模式S2B2C商城小程序,探讨其在沉浸式体验营销中的应用。通过对比传统品鉴、工厂参观等初级体验方式,分析沉浸式体验的优势与价值…...
大模型——基于Docker+DeepSeek+Dify :搭建企业级本地私有化知识库超详细教程
基于Docker+DeepSeek+Dify :搭建企业级本地私有化知识库超详细教程 下载安装Docker Docker官网:https://www.docker.com/ 自定义Docker安装路径 Docker默认安装在C盘,大小大概2.9G,做这行最忌讳的就是安装软件全装C盘,所以我调整了下安装路径。 新建安装目录:E:\MyS…...
