程序运行之动态链接一
相比静态链接,动态链接要复杂得多。但比静态链接更能节省空间。而且对于软件的升级以及插件的使用更快,更方便。比如在静态链接中有一个公共模块common.o 占据1M的空间,使用到common.o模块的程序有100个,那么每个都需要链接common.o。也就是会占据100M空间。如果有更多这样的程序,就会浪费更多的空间。再比如在软件升级的场景,common.o是第三方开发的,当第三方对该模块进行更新的时候,所有包含了common.o的模块都必须重新获取,链接然后发布。也就是程序任何一个位置的改动都会导致程序重新下载。
而动态链接就可以解决上面的这些问题,动态链接的基本思想是把程序按照模块拆分成各个相对独立部分,在程序运行时才将它们链接在一起形成一个完成的程序,而不是象静态链接一样把所有的程序模块都链接成一个单独的可执行文件。Windows下的动态链接文件是.dll为后缀名的文件,Linux下的动态链接文件是.so为后缀名的文件。
来用一个例子看下动态链接是如何工作的。创建pro1.c,pro2.c,Lib.c,Lib.h
pro1.c
#include "Lib.h"
int main()
{
foobar(1);
return 0;
}
pro2.c
#include "Lib.h"
int main()
{
foobar(2);
return 0;
}
Lib.c
#include <stdio.h>
void foobar(int i)
{
printf("Printing from Lib.so %d\n",i);
}
可以看到pro1.c和pro2.c都使用到了Lib.c中的foobar函数,那么就可以将Lib.c打包成一个共享库
执行gcc -fPIC -shared -o Lib.so Lib.c后,生成Lib.so文件
gcc -o pro1 pro1.c ./Lib.so和gcc -o pro2 pro2.c ./Lib.so进行链接.这里和静态链接不一样,pro1.c被链接成可执行文件的这一步,在静态链接中,这一步链接过程会把pro1.o 和Lib.o链接到一起产生可输出执行文件,但是在这里,Lib.o没有链接进来,链接的输入目标文件只有pro1.o
运行结果如下:
./pro1
Printing from Lib.so 1
./pro2
Printing from Lib.so 2
当pro1.c被编译成pro1.o的时候,编译器不知道foobar函数的地址。如果foobar是一个定义与其他静态文件目标模块中的函数,那么链接器会按照静态链接的规则,将pro1.o中的foobar引用重定位。如果foobar是一个定义在某个动态共享对象里面,那么链接器就会将整个符号的引用标记为一个动态链接的符号,那么链接器是如何知道foobar引用的是一个静态还是动态的对象呢,这就是我们要用到Lib.so的原因。把Lib.so做为链接的输入文件之一,那么链接器就知道foobar是一个定义在Lib.so的动态符号
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
2018-04-23 linux c编程:标准IO库