静态和动态库 |设置 1
编译 C 程序时,编译器会生成目标代码。生成目标代码后,编译器还会调用链接器。链接器的主要任务之一是使库函数(例如 printf()、scanf()、sqrt()、..等)的代码可用于您的程序。链接器可以通过两种方式完成此任务,通过将库函数的代码复制到您的目标代码,或通过进行一些安排以使库函数的完整代码不被复制,而是在运行时可用。
静态链接和静态库是链接器将所有使用的库函数复制到可执行文件的结果。静态链接会创建更大的二进制文件,并且需要更多的磁盘和主内存空间。静态库(静态链接的库)的示例是 Linux 中的.a文件和 Windows 中的.lib文件。
创建静态库的步骤让我们在 UNIX 或类 UNIX 操作系统中创建和使用静态库。
1.创建一个包含库中函数的 C 文件。
/* Filename: lib_mylib.c */
#include
void fun(void)
{
printf("fun() called from a static library");
}
为简单起见,我们仅创建了一个文件。我们还可以在一个库中创建多个文件。
2.为库创建头文件
/* Filename: lib_mylib.h */
void fun(void);
3.编译库文件。
gcc -c lib_mylib.c -o lib_mylib.o
4.创建静态库。这一步是将多个目标文件捆绑在一个静态库中(详见 ar)。这一步的输出是静态库。
ar rcs lib_mylib.a lib_mylib.o
5.现在我们的静态库可以使用了。此时我们可以将 lib_mylib.a 复制到其他地方来使用它。出于演示目的,让我们将库保存在当前目录中。
让我们创建一个使用上面创建的静态库的驱动程序。
1.创建一个带有main函数的C文件
/* filename: driver.c */
#include "lib_mylib.h"
void main()
{
fun();
}
2.编译驱动程序。
gcc -c driver.c -o driver.o
3.将编译好的驱动程序链接到静态库。请注意 -L 。用于告诉静态库在当前文件夹中(有关 -L 和 -l 选项的详细信息,请参见此处)。
gcc -o driver driver.o -L. -l_mylib
4.运行驱动程序
./driver
fun() called from a static library
以下是有关静态库的一些要点。
1.对于静态库,实际代码由链接器从库中提取,用于在您编译/构建应用程序时构建最终的可执行文件。
2.每个进程都有自己的代码和数据副本。在动态库的情况下,它只是代码共享,数据特定于每个进程。对于静态库,内存占用更大。例如,如果所有的窗口系统工具都是静态链接的,那么对于一个典型的用户来说,会浪费几十兆的内存,并且用户会因为大量的分页而变慢。
3.由于库代码在编译时连接,最终的可执行文件在运行时不依赖于库,即没有额外的运行时加载成本,这意味着您不需要携带库的副本,即正在使用,您可以控制一切,并且没有依赖性。
4.在静态库中,一旦所有内容都捆绑到您的应用程序中,您就不必担心客户端将在其系统上拥有正确的库(和版本)。
5.静态库的一个缺点是,对于静态库中的任何更改(升级),您每次都必须重新编译主程序。
6.即使是现在,静态库的主要优势之一是“速度”。静态库中不会有符号的动态查询。即使在今天,许多生产线软件也使用静态库。
动态链接和动态库动态链接不需要复制代码,只需将库的名称放在二进制文件中即可。实际链接发生在程序运行时,即二进制文件和库都在内存中。动态库(在运行时链接的库)的示例是 Linux 中的.so和 Windows 中的.dll 。
我们很快将介绍有关动态库的更多内容以及创建它们的步骤。