理解和创建Windows和Linux下的动态和静态库区别

article/2025/8/30 6:41:56

一、引言

在计算机编程的世界中,库是一个非常重要的改变。它的出现提供了一种共享和重用代码的可能性,复杂的程序因为动态库的出现而变得简洁和方便。然而,库并不是单一的:它们可以是动态的,也可以是静态的,每一种类型都有其使用场景。在本文中,我们将深入探讨动态库和静态库的概念,每种类型都有其优点和使用场景。讨论的范围将会集中两种最为常见的平台——Windows和Linux,主要内容还是帮助读者创建一个在自己平台下使用的动态库。

二、静态库和动态库基础知识

在顺利创建并使用动态库之前,让我们先来了解一下关于这两个库的概念。

2.1 动态库

动态库在程序实际运行时才会被加载到内存,多个程序可以共用这个动态库;Windows动态库以.dll结尾,而在Linux下则以.so结尾,其优点在于:

  • 节省内存。多个程序如果使用到了同一个动态库,仅需加载一次内存,从而达到节省内存的作用;
  • 模块化设计。动态库是一个模块化设计,每个库专注其特定的功能,增加了代码的可读性和维护性;
  • 简化更新和修复过程:因为是运行时才加载,如果符号保持不变,更新功能只需要替换掉原来的动态库即可;
  • 剥离常用函数,使得维护变得容易。这一个和模块化不同,模块化的功能单一,而剥离这个功能,主要是为了维护不同功能;
  • 跨语言兼容。不同语言也可以通过动态库使用对应的功能,使得其变得与语言无关;
  • 降低磁盘空间。同一个功能只需要存储一份动态库,而不需要每个程序都带有相应的代码段;

2.2 静态库

静态库在程序进行编译之时就被链接到程序中,每个程序都独占这部分功能代码。Windows中以.lib结尾,而Linux则以 .a结尾。一般而言[1],静态库含有对应功能的所有实现,其优点在于:

  • 独立性。静态库被链接到应用程序,将内容直接“注入”应用程序,不再需要存放着内容的动态库.dll,程序的部署和分发变得简单,无需担心目标系统是否具有对应的动态库;
  • 兼容性。版本冲突基本上不会出现,因为每个程序在编译之时就已经完成了版本冲突检查,如果有兼容性问题,编译器就被暴露出来了;
  • 性能。使用静态库的应用程序无需在运行时进行加载,降低了程序开销;
  • 安全性。静态库在编译时已经确定,攻击者更加难以通过替换库中的函数进恶意程序注入;(这就是为什么破解替换动态库就可以完成,大概率是因为替换掉了验证部分函数)

下面是一张比较动态库和静态库优缺点的表格:

动态库静态库
优点1. 节省内存 2. 支持模块化设计 3. 代码重用 4. 简化更新和修复过程 5. 跨语言兼容性 6. 减少磁盘空间的使用1. 独立性 2. 兼容性 3. 性能 4. 安全性
缺点1. 可能导致版本冲突 2. 运行时需要加载和链接库,可能影响性能1. 如果库代码更新,所有使用此库的程序都需要重新编译和链接 2. 程序文件大小通常比动态链接的程序更大

三、Windows下动态库和静态库的创建

3.1 如何创建一个动态库?(VS2022为例)

在这里插入图片描述
新建一个项目,选择Dynamic-Link Library(DLL),VS自动帮我们写了工程配置和部分用于优化的代码。对应源代码和头文件:

#include "pch.h" 
#include "addition.h"
int AddNumbers(int a, int b)
{return a + b;
}
#ifndef ADDITION_H
#define ADDITION_H__declspec(dllexport) int AddNumbers(int a, int b);#endif

在Windows平台上,默认情况下,函数和变量不会被自动导出为动态链接库(DLL)的一部分。如果你想要将函数或变量导出为DLL可见的导出项,需要显式地使用
__declspec(dllexport) 关键字进行标记。

在界面上选择目标库的架构和构建模式(Debug或者Release)。如下:
在这里插入图片描述
这里我选择了x64 Debug进行库的生成。在对应目录下可以找到如下内容:在这里插入图片描述
一共生成了四个文件分别是,dll exp lib pdb

  • dll (Dynamic Link Library)动态链接库:包含已编译的代码和数据,程序运行时将会动态加载;
  • exp(Exported File)导出文件。是关于dll的导出文件,描述导出函数和数据的名称和属性,含有导出数据和函数的符号信息,其他程序可以根据此文件进行符号解析和导入;
  • lib(Library):以lib结尾的文件按功能可以分为两部分,分别是导出库和一般意义上的静态链接库,不过Windows大多数情况都是以导出库形式导出所需要的动态库和函数
  • PDB(Program Database) PDB文件时调试符号文件,包含编译器生成的符号信息,用于映射源代码和二进制代码之间的关系,调试器能根据此文件,正确解析符号并提供详细的调试信息,比如函数名、行号等;

动态库导出将代码声明为导出,使用者将库中的函数标记为导入,以便使用其功能。

再次强调一下,在windows生成动态库过程中的lib和linux下a不一样,虽然他们都叫做静态库,前者是导出库,后者是含有具体代码的源文件二进制代码。

2.2 如何创建静态库?(以VS2022为例)

步骤和动态库基本相同:
在这里插入图片描述
在这里插入图片描述

  • idb(Intermediate Debug)中间调试文件,主要是为了加快重复生成静态库速度而出现的;
  • pdb 同动态库
  • lib 静态库,我们需要的

四、Linux下创建动态和静态库

4.1 如何创建一个静态库?(Linux下的CMake为例)

CMakeLists.txt:

cmake_minimum_required(VERSION 3.15)
project(buildLib)
set(LIBRARY_OUTPUT_PATH ../lib)
add_library(myLib STATIC library.cpp)

头文件:

//library.h
#ifndef ___LIBRARY_H
#define ___LIBRARY_H
void hello();
int myadd(int,int);
#endif 

源文件:

//library.cpp
#include <iostream>
#include "library.h"
void hello() {std::cout << "Hello, World!" << std::endl;
}
int myadd(int i,int j)
{return i+j;
}

相对简单一些,CMakeLists.txt同级目录下,可以看到生成的静态库libmyLib.a
在这里插入图片描述

4.2 如何创建一个动态库(Linux下的CMake为例)

Linux和Windows对于生成库的默认行为不同,前者在默认情况下是全部导出的,后者则是需要显式说明导出的符号。全部导出的好处是,可以减少繁琐的导出或者导入函数,缺点是体积变差。关键字 __declspec用于标识一个符号是否需要输出,如果在Windows下你需要全部输出,则设置变量CMAKE_WINDOWS_EXPORT_ALL_SYMBOLSON。下面是一个头文件示例(充分考虑了跨平台特性):

// library.h
#ifndef LIBRARY_H
#define LIBRARY_H// Check if we are on Windows
#ifdef _WIN32#define LIBRARY_API __declspec(dllexport)#define LIBRARY_LOCAL
// Check if we are on Unix (Linux, MacOS, etc.)
#elif __GNUC__ >= 4#define LIBRARY_API __attribute__ ((visibility ("default")))#define LIBRARY_LOCAL  __attribute__ ((visibility ("hidden")))
#else#define LIBRARY_API#define LIBRARY_LOCAL
#endif#ifdef BUILD_DLLLIBRARY_API void hello();LIBRARY_API int myadd(int,int);
#elsevoid hello();int myadd(int,int);
#endif#endif // LIBRARY_H

这个头文件做了一些宏处理,使用库和编译库都可以使用同一个头文件。

源文件:

//library.cpp
#include <iostream>
#include "library.h"
void hello() {std::cout << "Hello, World!" << std::endl;
}int myadd(int i,int j)
{return i+j;
}

CMakeLists.txt文件如下:

cmake_minimum_required(VERSION 3.15)
project(buildLib)
set(LIBRARY_OUTPUT_PATH ../lib)
add_library(myLib SHARED library.cpp)

请注意,如果你在Windows下使用这个CMakeLists.txt,如果你不手动添加一些导出关键字,生成动态库下不会出现Windows平台所需要的lib文件,除非你手动指定了导出的符号。

生成的文件如下:
在这里插入图片描述

五、小结

动态和静态库都是编程上常见的技术,它们各自有各自的特点。在Windows和Linux下他们都有相应的概念,对于Windows而言,为了简化动态库.dll的使用,Windows提出了一种.lib文件单独解决和揭示应用程序中使用符号的问题,而Linux则将这部分工作放入了.so中。需要特别注意的是Windows在使用动态库要使用到的.lib不一定与Linux.a一样,它有可能是为了解决动态库使用问题的。这就是为什么我们在Windows平台使用库的使用需要用到两个文件,一个是.dll 另一个则是lib;在Linux下,只需要在.a.so选择一个即可进行编译。为了保证动态库的使用效率,Windows默认情况下将动态库的所有符号都进行了隐藏,也就是默认不输出;而Linux则是将所有符号进行了输出,所幸的是,它们都有相应的关键字进行可见性的控制。之前遇到Windows生成不了.lib从而导致没有办法使用其中的库,其实就是因为没有相应标记输出的符号,如果没有输出符号,Windows当然也不会为你生成对应的代码。


[1] 在Windows中,.lib文件除了可以用作静态链接库外,还有另一种用途,就是用作动态链接库(.dll)的“导出库”。


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

相关文章

静态库与动态库的区别和使用

动静态库所用到的一些库文件&#xff1a; .o 是目标对象文件,相当于windows中的.obj文件。可由一个或多个.c /.cpp来生成 .a 为静态库&#xff0c;可以是一个或多个.o合在一起,用于静态连接&#xff1b;多个.o文件可以链接生成一个.exe的可执行文件。静态库在程序编译时会被连…

静态库和动态库的使用与区别

引文 库文件是计算机上的一类文件&#xff0c;可以理解为一种代码仓库&#xff0c;提供给使用者一些可以直接使用的变量、函数或类。 库文件分为两类&#xff1a; 静态库&#xff1a;在链接阶段&#xff0c;会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中…

【Linux静态库和动态库】

Linux静态库和动态库 1. 编译与ELF格式2. 库的基本概念3.静态库的制作&#xff1a;&#xff08;假设要将a.c、b.c制作成静态库&#xff09;4.静态库的常见操作5.静态库的使用6. 多个库的相互依赖举例1.(库文件制作、错误处理) 7.静态库和动态库的关系和区别8.动态库的制作软链接…

如何理解静态库与动态库

究竟什么是库&#xff1a; 日常生活中有很多所谓的库&#xff0c;比如车库啊&#xff0c;优衣库啊&#xff0c;甚至还有一库&#xff08;日语&#xff09;咳咳。然后对程序员来说&#xff0c;所谓的库&#xff0c;即是程序库&#xff0c;当一段代码十分耐用&#xff0c;又经过…

C++静态库与动态库的区别

文章目录 什么是库静态库Linux下创建与使用静态库Windows下创建与使用静态库 动态库Linux下创建与使用动态库Windows下创建与使用动态库 动态库的显式调用在Linux下显式调用动态库在Windows下显式调用动态库显式调用C动态库注意点 附件&#xff1a;Linux下库相关命令g(gcc)编译…

动态库静态库的区别

1、动态库以及静态库区别 静态库是函数和数据编译进一个二进制文件里面&#xff08;.lib文件&#xff09;&#xff0c;在使用静态库链接成可执行程序的时候&#xff0c;链接器会复制静态库内的函数和数据进可执行程序里面(.EXE文件)&#xff0c;所以在加载库的时候不需要加载相…

详谈静态库和动态库的区别

一、什么是库&#xff1a; 库是写好的&#xff0c;现有的&#xff0c;成熟的&#xff0c;可以复用的代码。现实中每个程序都要依赖很多基础的底层库&#xff0c;不可能每个人的代码都从零开始&#xff0c;因此库的存在意义非同寻常。 本质上来说&#xff0c;库是一种可执行代…

【C语言】详解#define,#ifdef,#ifndef,#elif,#undef,以及相关运算符

1.明示常量 #define 预处理指令结尾不带&#xff1b;&#xff08;分号&#xff09;&#xff0c;在预编译的过程中使用宏的地方会进行展开&#xff0c;是用多少次就展开多少次&#xff0c;但是只替换 不计算&#xff0c;预处理器在发现程序中的宏后&#xff0c;会用宏等价的替换…

Vue 项目报错:‘$‘ is not defined ( no-undef )

错误描述 报错如上图所示&#xff0c;错误原因是不认识 $ 符&#xff0c;他是 JQuery 中得符号&#xff0c;我也确实引入了 JQuery&#xff1a; 解决办法 在 vue 项目的根目录下创建一个 .eslinttrc.js 文件&#xff0c;文件内容如下&#xff1a; module.exports {root: true…

undefined和is not defined区别

undefined定义&#xff1a; undefined是javascript的一种基本数据类型&#xff0c;变量未赋值或者函数没有返回值时返回。 xxx is not defined是一种错误类型&#xff0c;其完整形式是&#xff1a;Uncaught ReferenceError: xxx is not defined&#xff08;未捕获的引用错误&a…

#define #undef等基本知识

1、预处理符号 例子&#xff1a; #include <stdio.h> #define DEBUG_PRINT printf("FILE %s line %d:" \"x%d, y%d, z%d," \__FILE__,__LINE__,x,y,z) //或者如下: //#define DEBUG_PRINT printf( "File %s line %d:…

undefined和is not defined一样吗?

https://blog.csdn.net/sheldon178/article/details/48298151/ undefined和is not defined&#xff0c;字面意思看来没什么两样&#xff0c;不都是未定义吗&#xff1f; 在JavaScript中&#xff0c;可并非如此。 undefined定义如下&#xff1a; undefined是javascript的一种…

C++中 #define 与 #undef

define 宏指令 #define 与 # include类似,它的好处呢就是速度快,使用define定义函数可以减少函数调用的额外开销 define 主要体现在2个地方 1 定义一个值 2 定义一个函数或者说功能 #include <iostream> using namespace std; // 定义一个值 #define HELLO_WORLD "…

#define #undef 使用

#define 是宏定义 #define 的用法是非常多功能的&#xff0c;它不止能实现常量宏定义&#xff0c;开关&#xff0c;还能实现函数 #undef 是取消宏定义 在undef后面要加上你要取消的宏定义 不想取消在后面可以瞎写但是不能为空 例子 #include "stdio.h"int main(…

C语言 #undef的用法

C语言中#undef的语法定义是&#xff1a;#undef 标识符&#xff0c;用来将前面定义的宏标识符取消定义。 然而&#xff0c;在实际应用中&#xff0c;#undef到底可以用来做什么&#xff1f; 整理了如下几种#undef的常见用法。 1. 防止宏定义冲突 在一个程序块中用完宏定义后&…

Perl学习-undef值和defined函数

undef值 undef是未定义的意思&#xff0c;在Perl中&#xff0c;会假设undef的变量时0或者空字符串 如果当成数字&#xff0c;就是0如果当成字符串&#xff0c;就是空字符串 当成数字 1 $n 1;2 3 while($n < 10){4 $sum $n;5 $n 2;6 }7 8 print "The tota…

吊打迅雷,最好用的BT种子下载器,下载不限速

今天小七要给大家带来的是一款安卓端BT下载器&#xff0c;用它来找片&#xff0c;下片&#xff0c;简直爽到极点&#xff0c;目前完全免费&#xff0c;无广告、无会员限制、极速下载、运行稳定支持多种格子解析、支持边下边播等等&#xff0c;拥有迅雷的所有功能&#xff0c;同…

比迅雷好用,下载速度快5倍的下载软件IDM(Internet Download Manager)

家好&#xff0c;很高兴大家阅读本文章&#xff0c;我一直在做自媒体&#xff0c;而且自媒体现在也当自己的一份工作来做了&#xff0c;那么在做自媒体的过程&#xff0c;肯定也会需要找素材&#xff0c;而在找素材的过程中需要用到下载工具&#xff0c;大家说说看现在国内&…

视频下载神器,支持 80+ 网站,比迅雷还快!

点击上方“逆锋起笔”&#xff0c;公众号回复 编程资源 领取大佬们推荐的学习资料开源最前线(ID:OpenSourceTop)编译 项目地址&#xff1a;https://github.com/soimort/you-get 今天&#xff0c;推荐一款下载神器&#xff0c;秒杀市面上你知道的所有下载工具&#xff0c;它就是…

迅雷自带的影音如何删除

1、首先下载迅雷影音&#xff1a; 2、下载之后&#xff0c;找到安装包&#xff0c;右键以压缩工具打开&#xff1a;并找到里面的XmpUninstall.exe文件---复制。 3、 复制到迅雷的安装路径下的这个路径&#xff1a;D:\Thunder Network\Thunder\Program\XMP\Program\XLGame&#…