静态链接库与动态链接库----C/C++

article/2025/9/29 9:13:03

  平时我们写程序都必须include很多头文件,因为可以避免重复造轮子,软件大厦可不是单靠一个人就能完成的。但是你是否知道引用的那些头文件中的函数是怎么被执行的呢?这就要牵扯到链接库了!!!大笑

  库有两种,一种是静态链接库,一种是动态链接库,不管是哪一种库,要使用它们,都要在程序中包含相应的include头文件。我们先来回顾一下程序编译的过程。如下图:













我们结合gcc指令来看一下每个阶段生成的文件:

gcc -c helloWorld.c

生成一个helloWorld.o文件,该文件是将源文件编译成的汇编文件,在链接之前,该文件不是可执行文件。

gcc -o helloWorld helloWorld.c
生成的是一个helloWorld的执行文件,格式为ELF(与windows不一样)。该文件为链接后的可执行文件。


1.静态链接库

  什么是静态链接呢?即在链接阶段,将源文件中用到的库函数与汇编生成的目标文件.o合并生成可执行文件。该可执行文件可能会比较大。

这种链接方式的好处是:方便程序移植,因为可执行程序与库函数再无关系,放在如何环境当中都可以执行。

缺点是:文件太大,一个全静态方式生成的简单print文件都有857K。而动态链接生成的一样的可执行文件却只要8.4K。




文件内容很简单,就是一个printf("hello world!\n");

因为包含库文件stdio,所以静态编译出的文件很大。如果你想尝试的话,可以这样编译:

gcc -static -o print print.c
在linux中,静态库为lib*.a,动态库为lib*.so。

下面我们来写一个库文件,然后生成一个静态库,然后尝试着调用一下它。

一个简单的add函数,头文件为







头文件对于的源文件:









下面我们来生成静态库:

输入:g++ -c add.cpp 生成.o目标文件

然后用ar命令进一步生成库libadd.a:

ar -crv libadd.a  add.o

这样就生成了一个静态链接库libadd.a。

下面我们来写一个测试文件:

<span style="font-size:18px;">#include <iostream>
#include "./addlib/add.h"
using namespace std;int main()
{int number1 = 10;int number2 = 90;cout << "the result is " << add(number1, number2) << endl;return 0;
}</span>
因为我的目录结构是add.cpp, addlib(文件夹),在addlib中是头文件和静态库,所以include用相对路径找到头文件add.h。

下面我们编译一下该文件:

g++ -o test test.cpp -L./addlib -ladd
-L是指定加载库文件的路径

-l是指定加载的库文件。

运行一下:





可见调用成功。


2.动态链接库

我们知道静态链接的话,文件会很大,往往实现很小的一个功能就需要占用很大的空间,而且每次库文件升级的话,都要重新编译源文件,很不方便。

具体下面如下:
















对于静态编译的程序1和程序2,都应用库staticMath。在内存中就又两份相同的staticMath目标文件,很浪费空间,一旦程序数量过多就很可能会内存不足。

这么大的内存才只能运行这几个程序,实在不甘心。

这样就又了动态库发挥威力的地方了。我们来看看动态链接的结果:




















我们看到在这种模型中,两个程序只应用一个库,这个目标文件在内存中只有一份,供所有程序使用。

并且在程序运行过程中动态调用库文件,很方便,又不占空间,但是动态链接有一个缺点就是可移植性太差,如果两台电脑运行环境不同,动态库存放的位置不一样,很可能导致程序运行失败。

在具体的应用中,静态与动态应当合理选择!!!

下面我们来生成一个动态库:

输入:g++ -fPIC -shared -o libadd.so add.cpp

这样就生成了一个libadd.so的动态库。

下面我们用动态链接的方式编译test.cpp。

输入:g++ -o test test.cpp -L./addlib -ladd

该命令和刚刚静态链接一样。注意-l后面接的是lib与so中间的库名称。

我们执行一下:




发现不行,因为执行程序找不到libadd.so。









可以看到test执行程序用到的libadd.so没有找到。。。

原因是在/etc/ld.so.conf文件中设置了动态链接库了寻找路径。





可以看到有很多路径设置文件,在ld.so.conf.d中,我们在下面添加一下我们libadd.so的路径。

然后再执行一下ldconfig命令。

这下就可以成功执行test文件了。

注意一下,有人说为什么我程序中extern int number;可以直接编译不需要什么静态链接库,动态链接库。那是因为你在链接时已经将number变量定义的目标文件.o和源文件进行了链接,如:gcc -o main main.o test.o。如果你只是单纯的用main.o进行链接,是生成不了可执行目标文件的,如:gcc -o main main.c会报告未定义的number引用。



综上说述,静态和动态链接库的选择要视情况而定。一般比较推荐动态链接方式,因为可以很好的节约内存,而且方便以后的库文件升级。


g++(gcc)编译选项

l -shared :指定生成动态链接库。

l -static :指定生成静态链接库。

l -fPIC :表示编译为位置独立的代码,用于编译共享库。目标文件需要创建成位置无关码,念上就是在可执行程序装载它们的时候,它们可以放在可执行程序的内存里的任何地方。

l -L. :表示要连接的库所在的目录。

l -l:指定链接时需要的动态库。编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.a/.so来确定库的名称。

l -Wall :生成所有警告信息。

l -ggdb :此选项将尽可能的生成gdb的可以使用的调试信息。

l -g :编译器在编译的时候产生调试信息。

l -c :只激活预处理、编译和汇编,也就是把程序做成目标文件(.o文件)

l   -Wl,options :把参数 (options) 传递给链接器 ld 。如果 options 中间有逗号 , 就将 options 分成多个选项 , 然后传递给链接程序。
















http://chatgpt.dhexx.cn/article/CN7iieBr.shtml

相关文章

【四、静态库与动态库(共享库)】揭开链接库的神秘面纱:手把手教你制作静态链接库与动态链接库

前言 不管是在 Windows 下开发&#xff0c;还是在 Linux 下开发&#xff0c;我们都会经常性的使用一些库文件&#xff0c;这些库文件的特点就是&#xff0c;我们可以看到接口的原型并通过这些接口来调用这个函数的功能&#xff0c;但是我们无法查看这个功能的实现。这就是库文…

静态链接库(.lib)和动态链接库(.dll)的使用

静态链接库(.lib)和动态链接库(.dll)的使用 文章目录 静态链接库(.lib)和动态链接库(.dll)的使用一、静态链接库1. 静态链接库概述2. 创建静态链接库3. 调用静态链接库 二、动态链接库(dynamic linking library)1. 动态链接库概述2. 创建动态链接库并导出函数导出函数两种方式1…

静态链接库

库 库的存在&#xff0c;大大方便了我们进行编程。因为有了库&#xff0c;我们不必再从0开始&#xff0c;例如我们大多数人C语言写的第一个程序Hello World!都是用了库函数。以printf为例&#xff0c;我们只需要在程序源代码中包含<stdio.h>这个头文件之后&#xff0c;就…

史上最全Java类型转换

讲类型转换之前&#xff0c;让我来贴张表 基本数据类型的表示范围 类型 长度 表示范围默认值byte8b-128&#xff5e;1270short16b-32768&#xff5e;327670int32b-21147483648&#xff5e;21474836470long64b-9223372036 854 775 808&#xff5e;9223372036 8547758070Lfloat3…

Java:类型转换

public class Demo04 {public static void main(String[] args) {//低--------------------------> 高// byte,short,char->int->long->float->doubleint i 128;byte b (byte) i ;//内存溢出//强制转换 &#xff08;类型&#xff09;变量名 高--低//自动转换…

java强转规则_java类型转换及其规则介绍

一、自动类型转换 整型、实型(常量)、字符型数据可以混合运算。运算中&#xff0c;不同类型的数据先转化为同一类型&#xff0c;然后进行运算。 数据类型转换必须满足如下规则&#xff1a; 1、不能对boolean类型进行类型转换。 2、不能把对象类型转换成不相关类的对象。 3、在把…

Sql-Java类型转换

Mysql-Java字段类型转换 mysql类型名大小用途对应Java类char0-255 bytes定长字符串 &#xff08;姓名、性别、学号&#xff09;Stringvarchar0-65535 bytes变长字符串&#xff08;比上面更长一点的那种&#xff09;Stringtinytext0-255 bytes比较短的那种文本数据&#xff08;…

JAVA类型转换及变量详解

类型转换 由于java是强类型语言&#xff0c;所以要进行有些运算的时候&#xff0c;需要用到类型转换。 byte&#xff08;1个字节&#xff09;,short&#xff08;2个字节&#xff09;,char&#xff08;2个字节&#xff09;----->int&#xff08;4个字节&#xff09;---->…

Java类型转换(自动类型转换+强制类型转换)

一、 自动类型转换(隐式类型转换) 整型、实型(常量)、字符型数据可以混合运算。运算中,不同类型的数据先转化为同一类型,然后进行运算。自动转换从低级到高级。 自动转换有以下规律: 1、小的类型自动转化为大的类型 2、整数类型可以自动转化为浮点类型,可能会产生舍入误…

Java的类型转换

需要类型转换的原因:因为Java是强类型的语言&#xff0c;所以有时可能要进行跨类型的运算&#xff0c;这就需要先进行类型转换&#xff0c;再进行运算。 类型转换分为&#xff1a; 强制类型转换(由高-->低时使用)&#xff0c;自动类型转换/ 隐式类型转换(由低-->高时使用…

java中的类型转换

java的基本数据类型 1.数值型&#xff1a;byte&#xff0c;short&#xff0c;int&#xff0c;long&#xff0c;float&#xff0c;double 2.字符型&#xff1a;char 3.布尔型&#xff1a;boolean 数据类型占据字节数byte1个字节short2个字节int4个字节long8个字节float4个字节…

Java中各种类型的转化

目录 一.Integer和int之间的类型转化 1.自动装箱 2.构造器方法 3.Integer.valueOf(int i) 二.Integer和String之间的类型转换 1.String转换为Integer 1.Integer.parseInt(String s) ​编辑 2.Integer.valueOf(String s) 2.Integer转换为String 1.Integer.toString() …

【JAVA】Java中的类型转换

目录 1.自动类型转换&#xff08;隐式转换&#xff0c;小类型转换为大类型&#xff09; 2.强制类型转换&#xff08;显示转换&#xff0c;大类型转换为小类型&#xff09; 3.小于4字节的类型转换问题 3.1 byte<->int 3.2 char<->int 3.3 String<->int …

Java 类型转换

一、自动类型转换(隐式类型转换) 整型、实型(常量)、字符型数据可以混合运算。不同类型的数据先转化为同类型再进行运算 自动转换按从低级到高级顺序: char ↓ Byte→short→int→long---›float→double 自动转换有以下规律&#xff1a; 小的类型自动转化为大的类型 整数…

java类型转换

文章目录 1、什么是类型转换&#xff1f; 2、掌握常见数据类型的范围大小 3、自动类型转换 3.1 int转换为double 3.2 char转换为int类型 4、强制类型转换 4.1、强制类型转换格式 5、注意事项 1、什么是类型转换&#xff1f; 在java中类型转换是一个非常重要的知识点。因…

java中常见类型的转换以及方法总结

1.char、String、int类型之间的转换 1.1 char和String的区别 char是表示的是字符&#xff0c;定义的时候用单引号&#xff0c;只能存储一个字符。例如; char‘d’. String表示的是字符串&#xff0c;定义的时候用双引号&#xff0c;可以存储一个或者多个字符。例如&#xff1…

CentOs 无法启动网络,用ip addr看不到IP地址

1.无法启动网卡&#xff0c;启动报file exist 原因1&#xff1a;可能是别的网络与网络冲突 解决&#xff1a;关闭NetworkManager 原因2&#xff1a;etc/sysconfig/network-scripts下的ifcfg开头的文件有内容有冲突 解决&#xff1a;删除一些对应文件 如果还是不行&#xf…

ip命令的使用方式(临时设定:ip addr ,ifconfig)

对外开放&#xff0c;能和主机直接进行交流的设备叫做网卡 内部交流&#xff0c;系统内部服务与服务之间的接口&#xff0c;为回环接口 lo##回环设备 [rootlocalhost 桌面]# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default…

ifconfig、ip addr、ip route用法总结

最近使用haproxykeepalived 负载均衡&#xff0c;发现虚拟IP有问题&#xff0c;配置文件里配的VIP是.4.143 ,但是执行 ip a 发现还有一个虚拟IP.4.134&#xff1b;应该是以前配置文件keepalived.conf里设置过VIP .4.134 以前的VIP一直没有消除&#xff0c;手动清除VIP&#xff…

Centos7中查看IP命令:IP addr

开机&#xff0c;输入用户名root和上篇文章中设置的密码&#xff0c;&#xff08;密码在Linux中是看不见的&#xff0c;但确实已经输入了&#xff09;&#xff0c;回车确定&#xff0c;显示时间信息&#xff08;没有设置时间&#xff09;&#xff0c;表示登陆成功。 在Centos7中…