首页 > 其他分享 >动态库与静态库

动态库与静态库

时间:2024-05-29 20:29:28浏览次数:12  
标签:文件 编译 静态 代码 int 动态

目录

认识动静态库

静态库

动态库

动静态库的优缺点

创建与使用动静态库

静态库的创建

静态库的使用

动态库的创建

 动态库的使用


认识动静态库

一个程序编译为可执行程序需要经历四个步骤:

  1. 预处理: 在此阶段,源代码会被预处理器处理。预处理器会执行如移除注释、展开宏定义、处理条件编译指令等任务。生成一个修改过的源代码文件,通常以.i(对于C语言)或.ii(对于C++)作为扩展名。

  2. 编译: 编译器接着对预处理后的源代码进行词法分析、语法分析、语义分析,并进行优化。这一系列过程将高级语言代码转换为汇编代码,文件拓展名为.s或.asm

  3. 汇编: 汇编器将汇编代码转换为目标代码,也就是机器语言,每个指令对应一条机器语言指令。这些指令是二进制格式的,可以直接被CPU执行。此步骤产生的文件是目标文件,常见扩展名为.o。

  4. 链接: 链接器将一个或多个目标文件以及需要的库文件组合起来,生成一个可执行文件。可执行文件包含了程序执行所需的所有代码和数据,操作系统可以直接加载并运行它。

库文件实际上就是已经编译和链接的代码集合,它们包含预先编译好的函数和数据,可供其他程序在链接阶段使用。库文件主要分为动态库与静态库,它们在链接和运行时的行为上有显著的不同。

静态库

静态库通常以  .a(Linux)  或   .lib(Windows)  作为文件扩展名。程序在编译链接的时候把库的代码链接到可执行文件中,即静态链接,链接后程序运行的时候将不再需要静态库。

动态库

动态库通常以  .so(Linux)  或  .dll(Windows)  作为文件扩展名。与静态库不同,动态库在程序运行时被加载,而不是在编译链接时。所以程序在运行时才需要动态库。

当程序启动时,动态库代码会被加载至内存,映射至进程地址空间的共享区,允许多个进程共享同一份库代码,程序中的函数调用会被解析为动态库中的函数地址。

动静态库的优缺点

动态库的优点

  • 节省磁盘空间:多个程序可以共享同一个动态库文件,减少了磁盘空间的使用。
  • 节省内存:如果多个进程使用了同一个动态库,操作系统可以确保所有进程共享同一份库的内存副本,节省内存资源。
  • 易于更新:开发者可以独立于应用程序更新动态库,用户只需要替换库文件而无需重新安装应用程序。
  • 版本控制:可以同时存在多个版本的动态库,便于过渡和兼容性管理。

动态库的缺点

  • 依赖性:程序运行时需要动态库,如果库文件缺失或版本不兼容,程序可能无法运行。
  • 安全风险:如果动态库被恶意篡改,会带来安全风险。
  • 兼容性问题:不同版本的动态库可能不兼容,需要仔细管理库的版本。

静态库的优点

  • 部署简单:静态库在编译时被整合到可执行文件中,部署时不需要额外的库文件。
  • 性能:由于所有必要的代码都包含在可执行文件中,程序启动和运行更快,省去了加载外部库的步骤。
  • 兼容性:不存在运行时找不到库或库版本不兼容的问题。
  • 安全性:因为库代码是编译进可执行文件的,所以更不容易被篡改。

静态库的缺点

  • 增加可执行文件大小:静态库的代码会被复制到每个使用它的可执行文件中,导致文件大小增加。
  • 更新不便:如果库的代码需要更新,所有使用该库的可执行文件都需要重新编译。
  • 磁盘空间:如果多个程序使用相同的静态库,相同的代码会被多次复制到不同的可执行文件中,浪费磁盘空间。
  • 内存使用:如果多个进程加载了包含相同静态库的可执行文件,相同的代码会被多次加载到内存中,浪费内存资源。

创建与使用动静态库

以上面五个文件为例

main.c

#include<stdio.h>
#include<add.h>
#include<sub.h>

int main()
{
    int x=9;
    int y=3;
    printf("x+y=%d\n",add(x,y));
    printf("x-y=%d\n",sub(x,y));
    return 0;
}

add.h

extern int add(int x,int y);

sub.h

extern int sub(int x,int y);

add.c

int add(int x,int y)
{
  return x+y;
}

sub.c

int sub(int x,int y)
{
  return x-y;
}

我们将 add.c ,add.h ,sub.c , sub.h 打包为一个库文件

静态库的创建

首先我们需要将源文件编译为 .o文件,我们使用gcc命令编译文件

gcc -c source.c -o source.o

现在我们有了所有需要的.o文件,您可以使用ar命令创建静态库。

ar rcs libmylib.a source.o

可以看到当前目录下生成了一个库文件。

我们可以用ar命令的-t选项和-v选项查看静态库当中的文件。

如果有更多文件要添加到库中,可以使用ar命令的q选项。

ar q libmylib.a another_source.o

如果我们要使用一个库时,必须有两个文件,一个是库的头文件,一个是库文件。

我们将编写的库文件与头文件单独存放在一个目录里。

静态库的使用

我们编译main.c,可以看到gcc报错了。

main.c:2:16: fatal error: add.h: No such file or directory #include<add.h> ^ compilation terminated. 

这个错误信息指出编译器在编译 main.c 文件时尝试包含一个名为 add.h 的头文件,但是在指定的搜索路径中没有找到这个文件。错误发生在 main.c 文件的第二行。

要想让编译器找到头文件与库文件,我们需要指定头文件和库文件所在的路径。

  • -I: 指定头文件路径。
  • -L:指定库文件路径。
  • -l: 指明库文件路径下需要链接的库

 现在让我们再试一次。

gcc -o test main.c -I ./include -L ./lib -l mymath 

可以看到程序成功编译并运行了。 那为什么我们平时使用c标准库时不需要指定呢?

C标准库的头文件与库文件已经安装在系统的默认包含路径和默认库路径中。编译器在编译时会自动搜索这些默认路径,因此不需要使用选项来指定。

所以我们还可以使用另一种方式,即将文件拷贝至默认路径。

可以看到同样成功了。 需要注意的是此时同样需要指定库名称。那为什么c标准库不需要呢?因为C标准库是每个C程序的基础依赖,为了保持兼容性和简化编译过程,编译器和链接器会自动处理标准库的链接。

动态库的创建

动态库的创建与静态库相似

同样是这五个文件,第一步生成.o文件。

 与静态库不同这里我们需要添加 -fpic 选项生成位置无关代码。

位置无关代码是一种编译技术,它允许编译后的程序或库在内存中的任何位置执行而无需修改。这种代码不依赖于固定的内存地址,而是使用相对于程序加载基址的偏移量或其他动态计算的地址来访问数据和代码。它具有重定位能力,可以在多个进程间共享,节省内存并提高效率。通常用于创建动态链接库,因为这些库可以在不同的程序中重用,而不受加载地址的影响。编译时需要特定的编译器选项(如gcc中的-fPIC)来生成。

接下来我们使用gcc创建动态库。

gcc -shared -o libmymath.so add.o sub.o

同样我们将编写的库文件与头文件单独存放在一个目录里。

 动态库的使用

与使用静态库相同,我们同样需要指定库文件和头文件的搜索路径。

我们发现程序不能直接执行并且报了错。这个错误信息表明程序在运行时尝试加载一个名为 libmymath.so 的动态库,但是没有找到这个库文件。我们在这里介绍两种方法

  • 将文件拷贝至库文件的默认搜索路径
  • 修改 LD_LIBRARY_PATH 条件变量。

拷贝文件到系统路径下

sudo cp ./libmymath.so /lib64

可以看到成功运行了。

修改条件变量

可以通过设置 LD_LIBRARY_PATH 环境变量来添加库文件的路径。 LD_LIBRARY_PATH 是一个在Linux上使用的环境变量,它为动态链接器提供一个搜索动态库的附加路径列表。当程序运行时,动态链接器会使用这个环境变量来查找程序依赖的动态库文件

export LD_LIBRARY_PATH=/home/user/test/ku/lib/libmymath:$LD_LIBRARY_PATH

可以看到程序成功运行了。

标签:文件,编译,静态,代码,int,动态
From: https://blog.csdn.net/2301_80926085/article/details/138914618

相关文章

  • 合约之间调用-如何实现函数静态调用?
    合约之间的函数调用EOA,externalownedaccount,外部账号,例如metamask调用最终总是由EOA发起的合约之间的调用使得一次完整的调用成为一个调用链条合约间调用过程调用者须持有被调用合约的地址得到被调用合约的信息将地址重载为被调用合约,调用它的函数最直接的调用方式(源......
  • 动态规划在图搜索中的应用:Floyd算法详解
    多源汇最短路问题-具有多个源点Floyd算法O(n^3)-动态规划给定一个n个点m条边的有向图,图中可能存在重边和自环,边权可能为负数。再给定k个询问,每个询问包含两个整数x和y,表示查询从点x到点y的最短距离,如果路径不存在,则输出“impossible”。数据保证图中不存在负权回路。......
  • C++:虚表指针、虚表、虚函数和动态多态
    classBase{public:virtualvoidshow(){std::cout<<"Baseshow"<<std::endl;}};classDerived_1:publicBase{public:voidshow()override{std::cout<<"Derivedshow"<<std::endl;}};class......
  • 读取静态资源图片
    点击查看代码//图标Resourceresource=newClassPathResource("file/内蒙章.png");InputStreamis=resource.getInputStream();byte[]fileByte=toByteArray(is);com.itextpdf......
  • vue3 组件的动态渲染 <component :is=“componentTag“ />
    1、动态渲染组件        <component:is=""></component>        通过isShow来切换显示A、B组件首先创建父组件.vue文件和两个子组件A、B文件,并引入。template:<div><h3>我是父组件dynamicComp.vue</h3><button@click="isShow=!isShow">切换......
  • 【Embedding合集】推荐系统/风控领域中动态连续型不定长序列数据处理方案
    【Embedding合集】推荐系统/风控领域中动态连续型不定长序列数据处理方案在推荐系统或是风控领域都存在这样一类动态连续型序列数据,如用户最近一个月消费记录,最近半年还款记录等等,这些序列数据的每一个元素都是连续型的数字,并且长度不定(每个用户消费的笔数都不一样),但这类动......
  • 深入探索C语言动态内存分配
    在编程的广阔天地里,C语言以其直接操控底层的能力和高效性能,至今仍占据着不可替代的地位。而在C语言的众多特性中,动态内存分配无疑是一项核心而又充满挑战的技术。本文将引领您深入探索这一技术的奥秘,从理论到实践,揭示动态内存分配的魅力所在。一、动态内存分配的必要性在程序......
  • Hadoop HDFS DataNode动态扩容机制
    胡弦,视频号2023年度优秀创作者,互联网大厂P8技术专家,SpringCloudAlibaba微服务架构实战派(上下册)和RocketMQ消息中间件实战派(上下册)的作者,资深架构师,技术负责人,极客时间训练营讲师,四维口袋KVP最具价值技术专家,技术领域专家团成员,2021电子工业出版社年度优秀作者,获得2023电......
  • cesium实现动态创建广告牌
    import{globalColorList,globalTextColorList}from"../js/positionTools.js";/***广告牌设备图标函数类*/exportdefaultclassDeviceMarker{constructor(arg){}/***初始化广告牌*@param{*}text文字*@param{*}iconType图表类型*......
  • python中的静态方法:@staticmethod 原理及应用
    @staticmethod是一个Python装饰器,用于声明一个方法为静态方法。静态方法不接受特定的实例或类参数(即没有self或cls参数),它们可以直接通过类调用,而不需要创建类的实例。静态方法的行为更接近于普通的函数。这是一个例子:classMyClass:@staticmethoddefmy_method(x,y)......