当前位置: 首页 > news >正文

[Linux系统编程] 静态库与动态库

一.库的概念

库是写好的现有的,成熟的,可以复用的代码。
本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。库有两种:静态库(.a、.lib)和动态库(.so、.dll)。
静态链接: 库随着程序一起编译,成为可执行程序的一部分,空间开销大,运行速度快
动态链接: 库只有在程序执行时被用到时才会被加入到内存中,空间开销小,运行较慢

二.Linux环境下静态库的制作及使用

首先使用-c选项,将c文件编译为二进制文件(.o),然后使用ar工具将二进制文件制作为静态库。

ar rcs [libXXXX.a] [所用到的.o文件]
其中,库文件名字XXXX可随意编写,但必须以lib为开头,.a为结尾

在这里插入图片描述
使用静态库的过程中,使用gcc编译c文件时,需要加上静态库的存储目录以及名称。
静态库使用,是将静态库实际编译至可执行文件。
如 : gcc test.c ./lib/libtest.a

注意:
源文件中必须要有函数的定义才可正常编译,若在源文件中没有包含库文件中的函数定义,系统会为其自动隐式定义,可正常执行,但会报错,使用-Wall选项可以查看有报错信息
所以在使用静态库的时候,一般都会在源文件中包含一个头文件,内部是所有的静态库函数定义。
在头文件中,要包含一个头文件守卫,防止重定义。

在这里插入图片描述

总结使用过程:
gcc [c文件] [库文件目录及名称] -I [头文件目录] -o [可执行文件命名]
如:gcc test.c ./a/libmymath.a -I ./b/ -o test.exe

gcc中选项:

-I 指定头文件目录
-o 指定文件名称
-Wall 查看报错信息
-g 增加调试语句
-c 只做预处理,编译,汇编操作,得到二进制文件,不进行连接操作。

三.Linux环境下动态库的制作及使用

第一步:
与静态库制作不同,在生成二进制文件(.o)时,需要生成与位置无关的代码,使用选项**-fPIC来实现。
原因:因为动态库是在程序运行时加载进入内存,其内部函数的地址绑定时间晚于源文件函数,只有动态库加载进入内存时,这些函数才有确切的地址(地址回填),而源文件中定义的函数在链接后就已经绑定地址。
第二步:
制作动态库,使用
gcc -shared -o [库名] [二进制文件]**
第三步:
使用动态库时,与静态链接不同,不会把动态库编译进入可执行文件,但需要指定库
-l 指定库名(去掉前缀lib 和 后缀so)
-L 指定目录
gcc [执行文件] -l [库名] -L [目录地址]
第四步:
此时的可执行文件还不可运行,这是因为动态链接器还无法工作,动态链接器需要找到库的存放目录,通过配置环境变量LD_LIBRARY_PATH 来指定。
执行一次环境变量的配置,在下次启动终端时不在生效,也就是临时生效。
为了解决这个问题,可修改.bashrc配置文件,加入如下语句,可以实现启动时自动读取库目录。
在这里插入图片描述

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

四.链接过程中的地址回填和数据段合并

1.什么是地址回填?
上文讲动态库链接时,动态库函数的地址会晚于源文件中函数的地址绑定,它们是在动态库加载进入内存后才进行绑定的,在加载入内存后,进行动态链接时会进行这个操作,被称为地址回填。
2.什么是数据段合并
其目的就是为了减少内存开销。
在Linux系统中,内存分页管理,一个页面多数为4K或8K

如下内存图中的可改数据段和不可改数据段,如果它们被分配的页面大小超过它们本身的所需要存储大小,就会降低内存的利用率。于是可以将某些数据段合并,用于增大内存利用率。这就是数据段合并。
在这里插入图片描述

GCC编译过程:

在这里插入图片描述程序中头文件与源文件不在同一目录下,需要使用gcc -I 指定头文件目录位置

在这里插入图片描述
使用C++ 11新标准时,需要加 -std=c++11
在这里插入图片描述

相关文章:

  • powershell 配合aria2实现简单的图片爬取
  • mvc的常见注解
  • SpringMVC 数据映射VC
  • 同比和环比
  • SpringBoot——整合Thymeleaf模板
  • static静态变量
  • 测试测试测试
  • 【Utils-实用工具】1 - 根据字节限制输入长度
  • [随笔] 在CSDN的6周年纪念日随笔
  • mybatis-plus中多条件查询使用and合or嵌套使用
  • Function Calling学习
  • 开源数据库同步工具DBSyncer
  • Altium Designer软件下载安装「专业PCB设计软件」Altium Designer安装包获取!
  • 【Linux 网络编程】协议的分层知识!
  • 专项技能训练五《云计算网络技术与应用》实训9 使用openVPN建立小型企业内网VPN环境
  • 【React系列】如何构建React应用程序
  • 【面试系列】之二:关于js原型
  • CoolViewPager:即刻刷新,自定义边缘效果颜色,双向自动循环,内置垂直切换效果,想要的都在这里...
  • Intervention/image 图片处理扩展包的安装和使用
  • JavaScript函数式编程(一)
  • Laravel深入学习6 - 应用体系结构:解耦事件处理器
  • Nginx 通过 Lua + Redis 实现动态封禁 IP
  • SpiderData 2019年2月16日 DApp数据排行榜
  • STAR法则
  • Transformer-XL: Unleashing the Potential of Attention Models
  • uni-app项目数字滚动
  • Vue官网教程学习过程中值得记录的一些事情
  • windows下使用nginx调试简介
  • Zepto.js源码学习之二
  • 初识MongoDB分片
  • 更好理解的面向对象的Javascript 1 —— 动态类型和多态
  • 海量大数据大屏分析展示一步到位:DataWorks数据服务+MaxCompute Lightning对接DataV最佳实践...
  • 技术:超级实用的电脑小技巧
  • 聊聊hikari连接池的leakDetectionThreshold
  • 聊聊sentinel的DegradeSlot
  • 一道闭包题引发的思考
  • 原生JS动态加载JS、CSS文件及代码脚本
  • Java总结 - String - 这篇请使劲喷我
  • PostgreSQL之连接数修改
  • 东超科技获得千万级Pre-A轮融资,投资方为中科创星 ...
  • ​3ds Max插件CG MAGIC图形板块为您提升线条效率!
  • ​LeetCode解法汇总518. 零钱兑换 II
  • # Swust 12th acm 邀请赛# [ K ] 三角形判定 [题解]
  • #{}和${}的区别?
  • (AtCoder Beginner Contest 340) -- F - S = 1 -- 题解
  • (bean配置类的注解开发)学习Spring的第十三天
  • (搬运以学习)flask 上下文的实现
  • (博弈 sg入门)kiki's game -- hdu -- 2147
  • (简单) HDU 2612 Find a way,BFS。
  • (三十)Flask之wtforms库【剖析源码上篇】
  • (十三)Java springcloud B2B2C o2o多用户商城 springcloud架构 - SSO单点登录之OAuth2.0 根据token获取用户信息(4)...
  • (一)Docker基本介绍
  • (转)淘淘商城系列——使用Spring来管理Redis单机版和集群版
  • .NET Core日志内容详解,详解不同日志级别的区别和有关日志记录的实用工具和第三方库详解与示例
  • .NET Framework 3.5中序列化成JSON数据及JSON数据的反序列化,以及jQuery的调用JSON