C语言动态链接与静态链接

什么是链接?

对于初学C语言的朋友,可能对链接这个概念有点陌生,这里简单介绍一下。我们的C代码编译生成可执行程序会经过如下过程:

C语言动态链接与静态链接_第1张图片

链接就是把目标文件与一些库文件生成可执行文件的一个过程。关于更详细的编译过程,可查阅往期笔记:C语言的编译过程

静态、动态链接?

1、什么是静态链接?

静态链接是由链接器在链接时将库的内容加入到可执行程序中的做法。链接器是一个独立程序,将一个或多个库或目标文件(先前由编译器或汇编器生成)链接到一块生成可执行程序。这里的库指的是静态链接库,Windows下以.lib为后缀,Linux下以.a为后缀。

2、什么是动态链接?

动态链接(Dynamic Linking),把链接这个过程推迟到了运行时再进行,在可执行文件装载时或运行时,由操作系统的装载程序加载库。这里的库指的是动态链接库,Windows下以.dll为后缀,Linux下以.so为后缀。值得一提的是,在Windows下的动态链接也可以用到.lib为后缀的文件,但这里的.lib文件叫做导入库,是由.dll文件生成的。

3、静态链接与动态链接的优缺点?

(1)静态链接的优缺点:

优点:

  • 代码装载速度快,执行速度略比动态链接库快;
  • 只需保证在开发者的计算机中有正确的.lib文件,在以二进制形式发布程序时不需考虑在用户的计算机上.lib文件是否存在及版本问题。

缺点:

  • 使用静态链接生成的可执行文件体积较大,包含相同的公共代码,造成浪费。

(2)动态链接的优缺点:

优点:

  • 生成的可执行文件较静态链接生成的可执行文件小;
  • 适用于大规模的软件开发,使开发过程独立、耦合度小,便于不同开发者和开发组织之间进行开发和测试;
  • 不同编程语言编写的程序只要按照函数调用约定就可以调用同一个DLL函数;
  • DLL文件与EXE文件独立,只要输出接口不变(即名称、参数、返回值类型和调用约定不变),更换DLL文件不会对EXE文件造成任何影响,因而极大地提高了可维护性和可扩展性;

缺点:

  • 使用动态链接库的应用程序不是自完备的,它依赖的DLL模块也要存在,如果使用载入时动态链接,程序启动时发现DLL不存在,系统将终止程序并给出错误信息;
  • 速度比静态链接慢;

静态、动态链接实验(windows)

下面通过实验来理解Windows下的静态链接与动态链接的过程。Windows下的静态链接、动态链接实验网上较多的是使用一些IDE如Visual Studio等通过图形界面来操作,这样就会掩盖了很多细节。

本篇笔记我们不使用IDE,而是以Windows平台搭配MinGW来演示,以便于日后我们在Linux下操作时可以比较快地进行切换。我们先编写如下代码(共三个文件):

文件1(main.c):

#include "test.h"

int main(void)
{
	print_hello();
	system("pause");
	return 0;
}

文件2(test.c):

#include "test.h"

void print_hello(void)
{
	printf("hello world\n");
}

文件3(test.h):

#ifndef __TEST_H
#define __TEST_H

#include 
#include 

void print_hello(void);

#endif

此时我们的代码目录如下:

C语言动态链接与静态链接_第2张图片

1、静态链接实验

进入我们的代码路径,输入命令:

gcc -c test.c main.c

C语言动态链接与静态链接_第3张图片

编译、汇编指定的源文件(也就是编译源文件),将每一个源文件编译成对应的目标文件。此时文件夹下多出了test.omain.o文件:

C语言动态链接与静态链接_第4张图片

接下来使用ar工具把test.omain.o打包成一个静态库文件lib_test.lib,输入命令:

ar rv lib_test.lib test.o main.o

C语言动态链接与静态链接_第5张图片

其实,用MinGW可以生成.a后缀和.lib后缀的静态链接库,这里生成的是.lib后缀的静态库。此时文件夹下多出了.lib文件:

C语言动态链接与静态链接_第6张图片

然后把这个静态库链接成可执行文件lib_test.exe,输入命令:

gcc lib_test.lib -o lib_test.exe

C语言动态链接与静态链接_第7张图片

此时文件夹下多出了可执行文件lib_test.exe

C语言动态链接与静态链接_第8张图片

双击运行:

C语言动态链接与静态链接_第9张图片

可见,运行结果与预期一致,说明我们使用静态链接的方式生成的可执行文件没问题。这个可执行文件的运行并不依赖于lib_test.lib文件,我们可以试着把这个文件删除之后再运行,仍然可以正常运行。

2、动态链接实验

我们把test.c编译成动态库文件dll_test.dll,输入命令:

gcc test.c -shared -o dll_test.dll 

C语言动态链接与静态链接_第10张图片

此时文件夹下多出了动态库文件dll_test.dll

C语言动态链接与静态链接_第11张图片

我们用该动态库文件dll_test.dllmain.c一起编译生成可执行文件dll_test.exe,输入命令:

gcc dll_test.dll main.c -o dll_test.exe

C语言动态链接与静态链接_第12张图片

此时文件夹下多出了可执行文件dll_test.exe

C语言动态链接与静态链接_第13张图片

双击运行:

C语言动态链接与静态链接_第14张图片

可见,运行结果与预期一致,说明我们使用动态链接的方式生成的可执行文件没问题。这个可执行文件的运行依赖于dll_test.dll文件,我们可以试着把这个文件删除之后再运行。运行出现如下错误:

C语言动态链接与静态链接_第15张图片

那是因为使用动态链接库的应用程序不是自完备的,它依赖的DLL模块也要存在。动态链接的方式使用得很广泛,比如我们电脑系统盘的System32文件夹下就有很多动态链接库文件:

C语言动态链接与静态链接_第16张图片

腾讯QQ安装目录下:

C语言动态链接与静态链接_第17张图片

上面使用的命令其实与Linux下操作的命令大多都很相似,我们只要明白这么一回事就可以很快地在Linux下进行操作。

以上就是本次的笔记分享,如有错误,欢迎指出!谢谢。

为了方便查阅笔记,我创建了一个公众号【嵌入式大杂烩】,感兴趣的朋友可以关注。

你可能感兴趣的:(C语言笔记)