库是什么?库就是将代码打包成一个文件,供程序在编译或运行时去调用,并且库中不能包含 main 函数。
静态库(.a)
静态库是程序在编译链接的时候就把库中的代码链接到可执行文件中,程序执行的时候将不再需要静态库。
静态库的创建
// add.h
#pragma once
int add(int a, int b);
// add.c
#include "add.h"
int add(int a, int b)
{
return a + b;
}
// sub.h
#pragma once
int sub(int a, int b);
// sub.c
#include "sub.h"
int sub(int a, int b)
{
return a - b;
}
首先将这两个文件编译成 .o 文件
再通过归档工具 ar 生成静态库,-rc 选项的意思是 replace and create
下面我们来测试一下我们的静态库
#include <stdio.h>
#include "add.h"
#include "sub.h"
int main()
{
printf("%d\n", add(10, 5));
printf("%d\n", sub(10, 5));
return 0;
}
在编译时加入我们的链接选项,并运行生成的可执行程序
现在我们来删掉这个静态库,再次运行可执行程序,可以看到程序依然可以正确执行,因为在链接时静态库中的代码已经全部被链接到了可执行文件中,在执行时是不需要静态库的。
动态库(lib***.so)
动态库又称为运行时库,程序在运行的时候才会去链接动态库中的代码,可执行文件中仅包含它到函数入口地址的一个表,所以动态库链接使得可执行文件更小,节省了磁盘空间。同时,操作系统采用虚拟内存的机制允许物理内存中的一份动态库要被用到该库的所有进程共用,节省了内存。
在可执行程序开始执行之前,操作系统会从磁盘上把动态库中的代码加载到内存中,这个过程称为动态链接。正是因为这样,当下一个程序使用同一个动态库时,就不需要再一次将动态库中的代码加载到内存中了,从而提高了运行的速度。
在 linux 下,有许多我们常用的动态库是放在 /usr/lib/ 目录下的,当我们使用动态库时,只需要加上链接选项就可以使用它,因为通常情况下在环境变量中就已经指定了动态库的寻找路径,如果我们想使用自己创建的动态库,那么就需要把这个动态库放入 /usr/lib/ 目录下,或者在链接时指明该动态库的路径。
动态库的创建
我们还是使用上面的 add.c 和 sub.c 来生成动态库。
-fPIC:产生位置无关码
-shared:表示生成共享库格式
动态库的命名规则:lib***.so
使用动态库来编译一下测试代码,运行可执行程序
可以看到,在编译时并没有任何问题,但运行时却告诉我们找不到指定的动态库,这是因为我们的动态库不在系统寻找动态库的默认路径下,我们可以使用下面的命令来将当前路径添加到系统寻找动态库的路径下,但这个方法指示临时的,还可以在环境变量中进行设置,这里不做具体的讲解。重新设置路径后,程序成功运行。
可以看到当我们的动态库不在指定路径下时程序都无法正常运行,更不用说当我们删除动态库,程序肯定是无法正常运行的。
静态库和动态库的比较
- 静态库链接的可执行文件在链接时将库中的代码全部链接到可执行程序中,使可执行文件变大;而动态库链接的可执行文件中仅包含它所用到的函数入口地址表,因此可执行文件的大小更小
- 静态库链接的可执行文件在运行时需要将链接到的库中的代码加载到内存中,降低了执行速度;而动态库在程序运行之前就将库中的代码加载到内存中,并且多个程序可以共享,提高了程序执行的速度
- 静态库链接的可执行文件将库中的代码全部链接到了可执行文件中,在执行时不受外界因素的影响;而动态库链接的可执行文件在执行时如果静态库丢失或不在指定路径下,程序将无法正确运行