我经常听到的术语“静态链接”和“动态链接”,常常在参考代码写入Ç , C ++或C# 。 它们是什么,究竟他们在谈论什么,什么是他们的连接?
Answer 1:
有(在大多数情况下,贴现解释代码)在从源代码获取(你写的)到可执行的代码(您运行的)两个阶段。
第一个是编译它变成源代码转换成目标模块。
第二,链接是什么结合目标模块在一起以形成一个可执行文件。
这种区别是用于制作,除其他事项外,允许第三方库将包含在可执行文件中没有你看到他们的源代码(如数据库访问,网络通信和图形用户界面库),或在不同语言的编译代码(例如C和汇编代码),然后将它们连接起来一起。
当你一个静态文件链接到一个可执行文件,该文件的内容都包含在链接时。 换句话说,该文件的内容用物理方法插入,你将运行可执行文件。
当您动态链接,指向该文件被链接(该文件的文件名,例如)包含在可执行文件,说的内容的文件不包含在链接时。 只有当你以后运行这些动态链接文件是在买了可执行文件,他们只买了到可执行文件,而不是磁盘上的一个的内存副本。
它基本上推迟链接的方法。 还有,不会在动态链接文件带来直到你真正尝试在它调用一个函数更加递延法(称为晚期在某些系统上绑定)。
静态链接的文件被“锁定”的可执行文件链接时,使他们永远不会改变。 通过一个可执行引用的动态链接文件,只需通过更换磁盘上的文件更改。
这允许更新功能,而无需重新链接代码; 装载机重新链接每次运行它的时候。
这是有好有坏 - 一方面,它可以更容易的更新和bug修复,另一方面它可以导致停止,如果更新不兼容的工作程序 - 这有时是可怕的“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随时都可能提供更新和bug修复。 如前所述,这既有优点也有缺点。
Answer 2:
我认为一个好的答案,这个问题应该解释链接是什么。
当你编译一些C代码(例如),它被翻译成机器语言。 个字节,运行时,使处理器加,减,比较,“GOTO”,读内存,写内存,之类的事情只是一个序列。 这东西是存储在对象(.o)文件。
现在,很久以前,计算机科学家发明了这个“子程序”的事情。 执行 - 这 - 块-的代码和回报 - 在这里。 才意识到,最有用的子程序可以存储在一个特殊的地方,并通过他们所需的任何程序中使用它是不会太长。
现在,在早期程序员会在这些子程序均位于内存地址冲。 像CALL 0x5A62
。 这是繁琐和有问题的应该永远需要改变那些内存地址。
所以,过程自动化。 你编写调用程序printf()
编译器不知道的内存地址printf
。 因此,编译器只是写CALL 0x0000
,并增加了一个音符到目标文件中说:“必须更换此为0x0000用的printf的存储位置”。
静态链接意味着链接程序(GNU的一个被称为LD )增加了printf
直接的机器代码,可执行文件,并改变0x0000到的地址printf
。 创建你的可执行文件时,会出现这种情况。
动态链接意味着上述步骤不会发生。 可执行文件仍然有一张纸条,上面写着“必须的printf的存储位置替换0x000的”。 操作系统的加载程序需要找到printf的代码,将其加载到内存中,并纠正调出地址, 每个程序运行时间 。
这是常见的程序调用一些功能,这将静态链接(如标准库函数像printf
这些动态链接通常是静态链接)等功能。 在静态的“成为部分”可执行文件和动态的可执行文件时运行“在加盟”。
有优点和缺点,以这两种方法,并有操作系统之间的差异。 但因为你没有问,我会在这里结束这个。
Answer 3:
静态链接库在编译时链接英寸 动态链接库在运行时加载。 静态链接烘烤库位到你的可执行文件。 动态链接仅烘烤到库的引用; 对于动态库位存在于其他地方,并可能在以后换出。
Answer 4:
由于没有上述职位的实际表现如何静态链接的东西,看到你这样做是正确的,所以我会解决这个问题:
一个简单的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位LSB的可执行文件,X86-64,版本1(SYSV),动态链接(使用共享库),用于GNU / Linux 2.6.26,BuildID [SHA1] = 0xf715572611a8b04f686809d90d1c0d75c6028f0f,不剥离”
相反,让我们静态链接的程序这个时候:
gcc simpleprog.c -static -o simpleprog
这个静态链接二进制运行文件将显示:
file simpleprog
“simpleprog:ELF 64位LSB的可执行文件,X86-64,版本1(GNU / Linux的),静态链接,用于GNU / Linux 2.6.26,BuildID [SHA1] = 0x8c0b12250801c5a7c7434647b7dc65a644d6132b,不剥离”
你可以看到它是愉快静态链接。 然而遗憾的是并不是所有的库都简单这样静态链接,可能需要延长使用工作libtool
或链接用手目标代码和C库。
幸运的是,像许多嵌入式C库musl
提供静态链接选项,几乎所有的如果不是所有的库。
现在strace
您已经创建二进制,你可以看到,有没有访问库的程序开始之前:
strace ./simpleprog
现在用的输出比较strace
对动态链接程序,你会看到,静态链接版本的strace的要短得多!
Answer 5:
(我不知道C#,但有趣的是,有一个VM语言静态连接的概念)
动态链接必须了解如何找到需要的功能,你只需从你的程序的参考。 你语言运行库或OS搜索文件系统,网络上的一段代码或编译的代码缓存,搭配参考,然后采取若干措施,以在存储器集成到你的程序的图像,如搬迁。 他们是在运行时全部完成。 这是可以做到手动或通过编译器。 没有与搞乱(即DLL地狱)的风险要更新的能力。
静态链接在那,你告诉编译器所有的功能部件,并指示它整合它们编译时完成。 有没有搜索,没有歧义,没有不重新编译更新的能力。 你所有的依赖是一个物理与程序的形象。