“静态链接”和“动态链接”是什么意思?

新手上路,请多包涵

我经常听到术语“静态链接”和“动态链接”,通常是指用 CC++C# 编写的代码。它们是什么,它们到底在说什么,它们在连接什么?

原文由 UnkwnTech 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 845
2 个回答

从源代码(你写的)到可执行代码(你运行的)有两个阶段(在大多数情况下,不考虑解释代码)。

第一个是将源代码转换为目标模块的编译。

第二个,链接,是将对象模块组合在一起以形成可执行文件。

区别在于,允许第三方库包含在您的可执行文件中,而您不会看到它们的源代码(例如用于数据库访问、网络通信和图形用户界面的库),或者用于编译不同语言的代码(例如 C 和汇编代码),然后将它们链接在一起。

当您将文件 静态 链接到可执行文件时,该文件的内容将包含在链接时。换句话说,文件的内容被物理插入到您将运行的可执行文件中。

当您 动态 链接时,指向正在链接的文件的指针(例如文件的文件名)包含在可执行文件中,并且在链接时不包含所述文件的内容。只有当您稍后 运行 可执行文件时,才会购买这些动态链接的文件,并且它们只被购买到可执行文件的内存副本中,而不是磁盘上的那个。

它基本上是一种延迟链接的方法。还有一种 延迟的方法(在某些系统上称为后期绑定),在您实际尝试调用其中的函数之前,它不会引入动态链接文件。

静态链接的文件在链接时被“锁定”到可执行文件,因此它们永远不会改变。可执行文件引用的动态链接文件只需替换磁盘上的文件即可更改。

这允许更新功能而无需重新链接代码;每次运行时加载程序都会重新链接。

这既好又坏 - 一方面,它允许更轻松的更新和错误修复,另一方面,如果更新不兼容,它可能导致程序停止工作 - 这有时是某些人可怕的“DLL地狱”的原因提到如果您将动态链接库替换为不兼容的库,则应用程序可能会被破坏(顺便说一句,这样做的开发人员应该期望受到追捕和严厉惩罚)。


作为一个 _例子_,让我们看看用户编译他们的 main.c 文件以进行静态和动态链接的情况。

 Phase     Static                    Dynamic
--------  ----------------------    ------------------------
          +---------+               +---------+
          | main.c  |               | main.c  |
          +---------+               +---------+
Compile........|.........................|...................
          +---------+ +---------+   +---------+ +--------+
          | main.o  | | crtlib  |   | main.o  | | crtimp |
          +---------+ +---------+   +---------+ +--------+
Link...........|..........|..............|...........|.......
               |          |              +-----------+
               |          |              |
          +---------+     |         +---------+ +--------+
          |  main   |-----+         |  main   | | crtdll |
          +---------+               +---------+ +--------+
Load/Run.......|.........................|..........|........
          +---------+               +---------+     |
          | main in |               | main in |-----+
          | memory  |               | memory  |
          +---------+               +---------+

您可以在静态情况下看到主程序和 C 运行时库在链接时(由开发人员)链接在一起。由于用户通常无法重新链接可执行文件,因此他们被库的行为所困扰。

在动态情况下,主程序与 C 运行时导入库链接(它声明了动态库中的内容,但实际上并未 定义 它)。即使缺少实际代码,这也允许链接器进行链接。

然后,在运行时,操作系统加载程序将主程序与 C 运行时 DLL(动态链接库或共享库或其他命名法)进行后期链接。

C 运行时的所有者可以随时插入新的 DLL 以提供更新或错误修复。如前所述,这既有优点也有缺点。

原文由 paxdiablo 发布,翻译遵循 CC BY-SA 3.0 许可协议

因为上述帖子都没有 真正展示如何 静态链接某些东西并看到你做对了,所以我将解决这个问题:

一个简单的C程序

#include <stdio.h>

int main(void)
{
    printf("This is a string\n");
    return 0;
}

动态链接C程序

gcc simpleprog.c -o simpleprog

并在二进制文件上运行 file

 file simpleprog

这将表明它是动态链接的,如下所示:

 simpleprog: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.26, BuildID[sha1]=0xf715572611a8b04f686809d90d1c0d75c6028f0f, not stripped

这次让我们静态链接程序:

 gcc simpleprog.c -static -o simpleprog

在这个静态链接的二进制文件上运行文件将显示:

 file simpleprog

现在结果将是

simpleprog: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.26, BuildID[sha1]=0x8c0b12250801c5a7c7434647b7dc65a644d6132b, not stripped

你可以看到它是愉快地静态链接的。但遗憾的是,并非所有库都可以简单地以这种方式静态链接,并且可能需要使用 libtool 或手动链接目标代码和 C 库进行扩展。

幸运的是,许多嵌入式 C 库,如 musl 为几乎所有( _如果不是全部_)库提供静态链接选项。

现在 strace 您创建的二进制文件,您可以看到在程序开始之前没有访问任何库:

 strace ./simpleprog

现在对比一下动态链接程序上 strace 的输出,你会发现静态链接版本的strace要短得多!

原文由 user4832408 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题