静态库、动态库详解

一口Linux 2021-10-13 11:50

C编译过程

在分析静态链接库、动态链接库之前,我们先来看一下计算机是怎么将.c文件一步步编译成可执行程序的,又是在哪一步使用到了静态库和动态库。

如下图,一个C代码变成可执行程序,主要运行在两个环境,即编译环境执行环境

编译环境 里面又包含了编译过程链接过程 两步。

编译过程 里面包含了预处理、编译、汇编 3步。

综上,就是我们常说的,C编译过程为:

  • 预处理

  • 编译

  • 汇编

  • 链接


预处理过程

预处理具体做的事情如下:

  1. 将所有的#define删除,并且展开所有的宏定义。

  2. 处理所有的条件编译指令,#ifdef #ifndef #endif

  3. 处理#include,将#include指向的文件插入到该行处

  4. 删除所有注释

  5. 添加行号和文件标示。这样在调试和编译出错的时候才能定位问题

使用gcc -E main.c -o main.i命令可以生成预编译之后的.i文件。

编译

编译具体做的事情如下:

  1. 词法分析

  2. 语法分析

  3. 语义分析

  4. 源代码转为汇编代码

使用gcc -S main.c -o main.sgcc -S main.i -o main.s命令都可以生成编译后的.s汇编文件。从这一步也可以看出main.cmain.i 所表达的内容是相同。

汇编

使用gcc -c main.c -o main.o命令,可以将汇编语言翻译成目标机器指令,生成.o文件。

链接

在实际开发中,我们一定是多文件编程,在汇编过后,单文件是不能工作的,需要多个文件相互结合起来,才能正常工作,这个结合的过程就叫做链接

上面讲到需要多个文件结合才能正常工作,这其中就包含了静态链接库和动态链接库。也就是说,动态链接库和静态链接库是在此处起作用的。

使用gcc main.c -o main命令,可以生成最终的可执行程序。

静态链接与动态链接的区别

静态链接方式 :在程序执行之前完成所有的组装工作,生成一个可执行的目标文件。windows下的库后缀为.lib,Linux下的库后缀为.a

动态链接方式 :在程序已经为了执行被装入内存之后完成链接工作,并且在内存中一般只保留该编译单元的一份拷贝windows下的库后缀为.dll,Linux下的库后缀为.so

综上 ,他们的一个主要区别在于链接的时机不同。

静态链接库

静态链接库 对应的链接方式为静态链接 。在链接阶段,会将汇编生成的目标.o文件与引用的库(静态链接库)一起链接打包到可执行文件中。静态链接库有以下特点

  1. 静态库对函数库的链接是放在编译时期完成的。

  2. 程序在运行时与函数库再无联系,移植方便。

  3. 浪费空间和资源。因为所有相关的目标文件与牵涉到的函数库被链接合成了一个可执行文件。

此处,我们以Linux下使用静态链接库为例(Windows下同理),作简要介绍

注: Linux静态库命名规范,必须是lib[your_library_name].alib 为前缀,your_library_name 是静态链接库名,扩展名为.a

生成静态链接库

我们实现准备好了main.c、test1.c、test1.h三个文件。

通过对C编译流程的分析,我们创建静态链接库有如下步骤

  1. 首先将源代码编译成.o文件
gcc -c test1.c -o test1.o
  1. .o文件使用ar工具,生成静态链接库
ar crv libtest1_lib.a test1.o

调用静态链接库

gcc main.c -o main -I ./ -L ./ -ltest1_lib

使用上述命令,可以生成一个基于静态链接库的test1_lib.a的main可执行程序。

其中

  • -I(大写的i)指定了头文件路径

  • -L(大写的L)指定了静态链接库的路径

  • -l(小写的L)指定了静态链接库名字

动态链接库

通过上述对静态链接库的分析,发现静态链接库的使用是简单的,也是很好理解的。但缺点 也是一目了然的,如

  1. 空间浪费严重。静态链接库在内存中存在多份拷贝的问题。

  2. 在程序的更新、部署、发布时,使用静态链接库会显得十分麻烦。

基于上述静态链接库的缺点,就有了动态链接库的使用。动态库在程序编译时并不会被连接到目标代码中,而是在程序运行时才被载入。

相对于静态链接库,优点 如下

  1. 不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题。

  2. 动态库在程序运行时才被载入,解决了静态库对程序的更新、部署和发布也会带来麻烦。用户只需要更新动态库即可,可实现增量更新

  3. 可以通过显示调用 动态链接库的方式,实现库的链接由程序员在程序中自由控制。

注: Linux动态库命名规范,必须是lib[your_library_name].solib 为前缀,your_library_name 是动态链接库名,扩展名为.so

生成动态链接库

  1. .c文件生成.so库,使用如下命令
gcc -fPIC -shared test1.c -o libtest1_lib.so

其中

-fPIC的作用为告诉编译器产生与位置无关代码。即产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的 PIC即Position-Independent Code的简写。

-shared的作用为生成共享目标文件。

调用动态链接库(隐式调用)

  1. 通过export将LD_LIBRARY_PATH环境变量设置为当前目录
export LD_LIBRARY_PATH=$(pwd)
  1. 同静态链接库一样,调用动态链接库,生成可执行程序
gcc main.c -o main -I ./ -L ./ -ltest1_lib

    -I(大写的i)、-L(大写的L)、-l(小写的L)同上。

调用动态链接库(显示调用)

上述介绍的动态库使用方法,同静态库一样属于隐式调用,编译的时候需要指定相应的库和查找路径。其实,动态链接库还可以支持显示调用。

显示调用动态链接库,需要用到#include<dlfcn.h>头文件,这个头文件里面包含了

  • void *dlopen ( const char * pathname, int mode );:函数以指定模式打开指定的动态连接库文件,并返回一个句柄给调用进程。

  • void*dlsym (void* handle,const char* symbol);:dlsym根据动态链接库操作句柄(pHandle)与符号(symbol),返回符号对应的地址。使用这个函数不但可以获取函数地址,也可以获取变量地址。

  • intdlclose (void *handle);:dlclose用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为0时,才会真正被系统卸载。

  • const char *dlerror(void);:当动态链接库操作函数执行失败时,dlerror可以返回出错信息,返回值为NULL时表示操作函数执行成功。

同上,我们还是准备好了main.c、test1.c、test1.h三个文件。并且已经通过test1.c文件生成了一个动态链接库libtest1_lib.so,test1.c文件里面定义了一个void test1_fun(void)函数,我们编写main.c代码如下

#include "stdio.h"
#include <dlfcn.h>

void main()
{
  void* handler = dlopen("./libtest1_lib.so",RTLD_NOW | RTLD_DEEPBIND);

  if(dlerror() != NULL)
  {
        printf("%s",dlerror());
    }

  void(*test1_fun)()=dlsym(handler,"test1_fun");
    if(dlerror()!=NULL)
  {
    printf("%s",dlerror());
    }

  test1_fun();

  dlclose(handler);
}

  • 第2行,引用了dlfcn头文件

  • 第6行,以RTLD_NOW和RTLD_DEEPBIND方式打开了libtest1_lib.so库。

#define RTLD_LAZY           0x00001  /* Lazy function call binding.  */
#define RTLD_NOW            0x00002  /* Immediate function call binding.  */
#define RTLD_BINDING_MASK   0x3  /* Mask of binding time value.  */
#define RTLD_NOLOAD         0x00004  /* Do not load the object.  */
#define RTLD_DEEPBIND       0x00008  /* Use deep binding.  */
  • 第13行获取libtest1_lib.so库中test1_fun函数的地址

  • 第19行,运行test1_fun函数

  • 第21行,关闭libtest1_lib.so库。

-----END-----

关注,回复【1024】海量Linux资料赠送

精彩文章合集

linux入门

C语言
Linux驱动
ARM
计算机网络
粉丝问答
所有原创
点击“阅读原文”查看更多分享,欢迎点分享、收藏、点赞、在看
一口Linux 写点代码,写点人生!
评论
  • 铁氧体芯片是一种基于铁氧体磁性材料制成的芯片,在通信、传感器、储能等领域有着广泛的应用。铁氧体磁性材料能够通过外加磁场调控其导电性质和反射性质,因此在信号处理和传感器技术方面有着独特的优势。以下是对半导体划片机在铁氧体划切领域应用的详细阐述: 一、半导体划片机的工作原理与特点半导体划片机是一种使用刀片或通过激光等方式高精度切割被加工物的装置,是半导体后道封测中晶圆切割和WLP切割环节的关键设备。它结合了水气电、空气静压高速主轴、精密机械传动、传感器及自动化控制等先进技术,具有高精度、高
    博捷芯划片机 2024-12-12 09:16 111浏览
  • 习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习笔记&记录学习习笔记&记学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记
    youyeye 2024-12-12 10:13 79浏览
  • 全球智能电视时代来临这年头若是消费者想随意地从各个通路中选购电视时,不难发现目前市场上的产品都已是具有智能联网功能的智能电视了,可以宣告智能电视的普及时代已到临!Google从2021年开始大力推广Google TV(即原Android TV的升级版),其他各大品牌商也都跟进推出搭载Google TV操作系统的机种,除了Google TV外,LG、Samsung、Panasonic等大厂牌也开发出自家的智能电视平台,可以看出各家业者都一致地看好这块大饼。智能电视的Wi-Fi连线怎么消失了?智能电
    百佳泰测试实验室 2024-12-12 17:33 119浏览
  • RK3506 是瑞芯微推出的MPU产品,芯片制程为22nm,定位于轻量级、低成本解决方案。该MPU具有低功耗、外设接口丰富、实时性高的特点,适合用多种工商业场景。本文将基于RK3506的设计特点,为大家分析其应用场景。RK3506核心板主要分为三个型号,各型号间的区别如下图:​图 1  RK3506核心板处理器型号场景1:显示HMIRK3506核心板显示接口支持RGB、MIPI、QSPI输出,且支持2D图形加速,轻松运行QT、LVGL等GUI,最快3S内开
    万象奥科 2024-12-11 15:42 123浏览
  • 首先在gitee上打个广告:ad5d2f3b647444a88b6f7f9555fd681f.mp4 · 丙丁先生/香河英茂工作室中国 - Gitee.com丙丁先生 (mr-bingding) - Gitee.com2024年对我来说是充满挑战和机遇的一年。在这一年里,我不仅进行了多个开发板的测评,还尝试了多种不同的项目和技术。今天,我想分享一下这一年的故事,希望能给大家带来一些启发和乐趣。 年初的时候,我开始对各种开发板进行测评。从STM32WBA55CG到瑞萨、平头哥和平海的开发板,我都
    丙丁先生 2024-12-11 20:14 94浏览
  • 本文介绍瑞芯微RK3588主板/开发板Android12系统下,APK签名文件生成方法。触觉智能EVB3588开发板演示,搭载了瑞芯微RK3588芯片,该开发板是核心板加底板设计,音视频接口、通信接口等各类接口一应俱全,可帮助企业提高产品开发效率,缩短上市时间,降低成本和设计风险。工具准备下载Keytool-ImportKeyPair工具在源码:build/target/product/security/系统初始签名文件目录中,将以下三个文件拷贝出来:platform.pem;platform.
    Industio_触觉智能 2024-12-12 10:27 115浏览
  • 习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习笔记&记录学习习笔记&记学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记
    youyeye 2024-12-11 17:58 108浏览
  • 时源芯微——RE超标整机定位与解决详细流程一、 初步测量与问题确认使用专业的电磁辐射测量设备,对整机的辐射发射进行精确测量。确认是否存在RE超标问题,并记录超标频段和幅度。二、电缆检查与处理若存在信号电缆:步骤一:拔掉所有信号电缆,仅保留电源线,再次测量整机的辐射发射。若测量合格:判定问题出在信号电缆上,可能是电缆的共模电流导致。逐一连接信号电缆,每次连接后测量,定位具体哪根电缆或接口导致超标。对问题电缆进行处理,如加共模扼流圈、滤波器,或优化电缆布局和屏蔽。重新连接所有电缆,再次测量
    时源芯微 2024-12-11 17:11 141浏览
  • 应用环境与极具挑战性的测试需求在服务器制造领域里,系统整合测试(System Integration Test;SIT)是确保产品质量和性能的关键步骤。随着服务器系统的复杂性不断提升,包括:多种硬件组件、操作系统、虚拟化平台以及各种应用程序和服务的整合,服务器制造商面临着更有挑战性的测试需求。这些挑战主要体现在以下五个方面:1. 硬件和软件的高度整合:现代服务器通常包括多个处理器、内存模块、储存设备和网络接口。这些硬件组件必须与操作系统及应用软件无缝整合。SIT测试可以帮助制造商确保这些不同组件
    百佳泰测试实验室 2024-12-12 17:45 113浏览
  • 在智能化技术快速发展当下,图像数据的采集与处理逐渐成为自动驾驶、工业等领域的一项关键技术。高质量的图像数据采集与算法集成测试都是确保系统性能和可靠性的关键。随着技术的不断进步,对于图像数据的采集、处理和分析的需求日益增长,这不仅要求我们拥有高性能的相机硬件,还要求我们能够高效地集成和测试各种算法。我们探索了一种多源相机数据采集与算法集成测试方案,能够满足不同应用场景下对图像采集和算法测试的多样化需求,确保数据的准确性和算法的有效性。一、相机组成相机一般由镜头(Lens),图像传感器(Image
    康谋 2024-12-12 09:45 117浏览
  • 一、SAE J1939协议概述SAE J1939协议是由美国汽车工程师协会(SAE,Society of Automotive Engineers)定义的一种用于重型车辆和工业设备中的通信协议,主要应用于车辆和设备之间的实时数据交换。J1939基于CAN(Controller Area Network)总线技术,使用29bit的扩展标识符和扩展数据帧,CAN通信速率为250Kbps,用于车载电子控制单元(ECU)之间的通信和控制。小北同学在之前也对J1939协议做过扫盲科普【科普系列】SAE J
    北汇信息 2024-12-11 15:45 140浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦