DLL和LIB文件 - 是什么以及为什么需要它们?

299

除了它们包含程序必需的关键代码(库)外,我对DLL和LIB的了解很少。但是编译器为什么要生成它们呢?将所有代码包含在单个可执行文件中不是更容易吗?DLL和LIB之间有什么区别?

我对DLL和LIB的了解很少。但是编译器为什么要生成它们呢?将所有代码包含在单个可执行文件中不是更容易吗?DLL和LIB之间有什么区别?

https://fileinfo.com/extension/lib - Channa
5个回答

400
有静态库(LIB)和动态库(DLL)-但请注意,.LIB文件既可以是包含对象文件的静态库,也可以是包含符号以允许链接器链接到DLL的导入库。
使用库是因为您可能有要在多个程序中使用的代码。例如,如果您编写一个计算字符串中字符数的函数,则该函数将在许多程序中很有用。一旦该函数正确运行,您不想每次使用它时都重新编译代码,因此将该函数的可执行代码放入库中,链接器可以提取并将已编译的代码插入到您的程序中。由于这个原因,静态库有时被称为“档案”。
动态库更进一步。在每个程序中有多个副本占用空间的库函数似乎是浪费的。他们为什么不能共享一个函数的副本?这就是动态库的用途。当加载进内存时,它可以通过映射到你的程序来运行库代码,而不是在编译时将库代码构建到你的程序中。同时使用相同函数的多个程序可以共享一个副本,从而节省内存。实际上,你可以根据你的代码路径只在需要时加载动态库。如果你不打印任何东西,那么没有必要将打印例程占用内存。另一方面,这意味着你必须在每台运行程序的机器上都安装动态库的副本。这会产生自己的一系列问题。
例如,几乎所有用'C'编写的程序都需要来自一个名为'C运行时库'的库中的函数,虽然很少有程序需要所有函数。C运行时库有静态和动态两个版本,因此您可以根据具体需求决定您的程序使用哪个版本。

94
原来,.LIB 文件既可以是静态库(包含目标文件),也可以是导入库(包含符号以允许链接器链接到 DLL)。我想知道这是为什么。 - Lumi
3
好的解释!代码是共享的,而数据(默认情况下)不在使用 Dll 的应用程序之间共享。 - mox
13
@Lumi:说得好。在 DLL 中,我们有两种类型的链接方式。隐式链接是指当我们拥有由 DLL 创建者提供的 .lib 文件和适当的头文件时,这个 .lib 文件仅仅是目标 DLL 的描述符,它包括地址、入口点等信息但没有代码,必须传递给链接器。第二种是 显式链接,即通过手动使用 LoadLibrary 函数加载 DLL 来使用它。在这种类型中,我们不需要那个 .lib 文件,但我们必须花费一点力气来查找 DLL 的导出项及其地址,并通过指针调用这些函数。 - itachi
1
请问,如果我的项目中包含头文件(.h)和源文件(.c),那么库文件是否必要用于可执行文件的编译和运行?我并不是在讨论这样做的利弊,只是想知道它是否能够编译和运行。 - platinoob_

45
另一个方面是安全(混淆)。一旦从主应用程序中提取了一段代码并放入“分离的”动态链接库中,攻击、分析(反向工程)代码就更容易,因为它已经被隔离。当同样的代码被保留在LIB库中时,它是编译(链接)目标应用程序的一部分,因此很难将这段代码与目标二进制文件的其他部分区分开来。

安全方面对我来说是新的。在C#应用程序调用本地未托管的C++ dll的情况下,上述推理是否成立? - Martin
1
但是LIB也是被隔离的,不是吗?因此,攻击者可以简单地分析LIB。或者说,LIB不可供公众访问是一个常见情况吗? - Nick Russler
10
根据编译器进程来看,LIB也是"隔离的",但一旦链接器将各部分组合在一起,LIB就成为EXE的一部分,无法与您自己的代码区分开来。 - mox

21

创建DLL/LIB的一个重要原因是为了重用和重定位,而不仅仅是将代码编译成可执行文件。平均而言,Java或.NET应用程序(例如)很可能会使用几个第三方(或框架)库。与必须将所有第三方代码编译到应用程序中相比,仅针对预构建库进行编译要容易得多且更快。将代码编译为库还可以鼓励良好的设计实践,例如设计适用于不同类型应用程序的类。


12

DLL是一组函数的库,可供其他可执行程序共享使用。只需查看您的windows/system32目录,您就会发现其中有数十个DLL文件。当您的程序创建一个DLL时,通常还会创建一个lib文件,以便应用程序*.exe程序可以解析在DLL中声明的符号。

.lib是一组函数库,这些函数与程序静态链接 -- 它们不会被其他程序共享。每个链接到*.lib文件的程序都拥有该文件中的所有代码。如果您有两个程序A.exe和B.exe,它们都链接到C.lib,则每个A和B都将包含C.lib中的代码。

如何创建DLL和Lib取决于您使用的编译器。每个编译器的实现方法都不同。


6

另一个区别在于性能。

由于DLL是由.exe文件在运行时加载的,因此.exe文件和DLL使用共享内存概念,因此相对于静态链接,性能较低。

另一方面,.lib是在编译时静态链接到每个请求的进程中的代码。因此,.exe文件将具有单一内存,从而提高了进程的性能。


1
从库或DLL运行的代码之间没有性能影响。 - Kyberias
这个答案让我有点担心,但上面的评论是正确的。正如下面的SO答案所述,性能差异(如果有)可以忽略不计:https://dev59.com/1G855IYBdhLWcg3wXTAI#4385050 - DragonJawad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接