对于初学C语言的朋友,可能对链接
这个概念有点陌生,这里简单介绍一下。我们的C代码编译生成可执行程序会经过如下过程:
链接就是把目标文件与一些库文件生成可执行文件的一个过程。关于更详细的编译过程,可查阅往期笔记:C语言的编译过程
1、什么是静态链接?
静态链接是由链接器在链接时将库的内容加入到可执行程序中的做法。链接器是一个独立程序,将一个或多个库或目标文件(先前由编译器或汇编器生成)链接到一块生成可执行程序。这里的库指的是静态链接库,Windows下以.lib为后缀,Linux下以.a为后缀。
2、什么是动态链接?
动态链接(Dynamic Linking
),把链接这个过程推迟到了运行时再进行,在可执行文件装载时或运行时,由操作系统的装载程序加载库。这里的库指的是动态链接库,Windows下以.dll为后缀,Linux下以.so为后缀。值得一提的是,在Windows下的动态链接也可以用到.lib为后缀的文件,但这里的.lib文件叫做导入库,是由.dll文件生成的。
3、静态链接与动态链接的优缺点?
(1)静态链接的优缺点:
优点:
缺点:
(2)动态链接的优缺点:
优点:
缺点:
下面通过实验来理解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
此时我们的代码目录如下:
1、静态链接实验
进入我们的代码路径,输入命令:
gcc -c test.c main.c
编译、汇编指定的源文件(也就是编译源文件),将每一个源文件编译成对应的目标文件。此时文件夹下多出了test.o
和main.o
文件:
接下来使用ar
工具把test.o
和main.o
打包成一个静态库文件lib_test.lib
,输入命令:
ar rv lib_test.lib test.o main.o
其实,用MinGW可以生成.a后缀和.lib后缀的静态链接库,这里生成的是.lib后缀的静态库。此时文件夹下多出了.lib文件:
然后把这个静态库链接成可执行文件lib_test.exe
,输入命令:
gcc lib_test.lib -o lib_test.exe
此时文件夹下多出了可执行文件lib_test.exe
:
双击运行:
可见,运行结果与预期一致,说明我们使用静态链接的方式生成的可执行文件没问题。这个可执行文件的运行并不依赖于lib_test.lib
文件,我们可以试着把这个文件删除之后再运行,仍然可以正常运行。
2、动态链接实验
我们把test.c
编译成动态库文件dll_test.dll
,输入命令:
gcc test.c -shared -o dll_test.dll
此时文件夹下多出了动态库文件dll_test.dll
:
我们用该动态库文件dll_test.dll
与main.c
一起编译生成可执行文件dll_test.exe
,输入命令:
gcc dll_test.dll main.c -o dll_test.exe
此时文件夹下多出了可执行文件dll_test.exe
:
双击运行:
可见,运行结果与预期一致,说明我们使用动态链接的方式生成的可执行文件没问题。这个可执行文件的运行依赖于dll_test.dll
文件,我们可以试着把这个文件删除之后再运行。运行出现如下错误:
那是因为使用动态链接库的应用程序不是自完备的,它依赖的DLL模块也要存在。动态链接的方式使用得很广泛,比如我们电脑系统盘的System32
文件夹下就有很多动态链接库文件:
腾讯QQ安装目录下:
上面使用的命令其实与Linux下操作的命令大多都很相似,我们只要明白这么一回事就可以很快地在Linux下进行操作。
以上就是本次的笔记分享,如有错误,欢迎指出!谢谢。
为了方便查阅笔记,我创建了一个公众号【嵌入式大杂烩】,感兴趣的朋友可以关注。