静态库概述(度娘一波)
静态库,也称归档文件(archive),是指在我们的应用中,有一些公共代码是需要反复使用,就把这些代码编译为“库”文件;在链接步骤中,连接器将从库文件取得所需的代码,复制到生成的可执行文件中的这种库。
程序编译一般需经预处理、编译、汇编和链接几个步骤。静态库特点是可执行文件中包含了库代码的一份完整拷贝;缺点就是被多次使用就会有多份冗余拷贝。
静态库(*.a)(这里的.a指的是)和动态库(*.)是两种共享程序代码的方式,它们的区别是:静态库在程序的链接阶段被复制到了程序中,和程序运行的时候没有关系;动态库在链接阶段没有被复制到程序中,而是程序在运行时由系统动态加载到内存中供程序调用。使用动态库的优点是系统只需载入一次动态库,不同的程序可以得到内存中相同的动态库的副本,因此节省了很多内存。
创建和使用静态库
编译过程一览
预处理 .i .ii文件 gcc -E hello.cpp -o hello.i
编译 .s文件 gcc -S hello.cpp -o hello.s
汇编 .o .obj文件 gcc -c hello.cpp -o hello.o
链接 .lib .a文件
假设我们现在有两个文件,main.cpp和func.cpp,main.cpp使用了func.cpp里面的函数,那么在汇编完成产生目标文件后,链接器会在链接时将两个文件链接成可执行文件(.out)文件。下面是例子
//main.c
#include<stdlib.h>
#include"lib.h" //头文件
int main()
{
func("Hello World"); //声明在lib.h头文件里
exit(0);
}
//头文件 lib.h
void func(char* );
//func.c
#include<stdio.h>
void func(char* a)
{
printf("%s\n",a);
}
过程:
1. 使用gcc -c 生成目标文件
gcc -c main.c func.c
执行完会生成main.o和func.o目标文件
2. 接下来要链接成可执行文件
gcc -o proexec main.o func.o
这条命令会生成一个名为proexec的可执行文件,直接运行就可以看到输出“hello world”。
上面编译过程特地将链接过程单独分出来,是因为我们在使用静态库的时候,其实是在链接的时候和目标文件一起生成可执行文件的过程。假设我们又有一个文件,里面有其他我们没用上的函数
//otherfunc.c
#include<stdlio.h>
void otherfunc(int arg)
{
printf("other func\n");
}
我们不希望使用其他函数的时候还得一个一个写命令,希望把他们打包到一个静态库文件里,后面使用到任何在这个库里面到函数,只需要加入这个库的路径就可以链接成可执行文件了,而不用gcc -o x.o y.o z.o这么麻烦。我们需要如下命令:
gcc -c other.c //编译成目标文件
ar crv lib.a other.o func.o //打包成静态库
执行完后,会生成静态库文件。
gcc -o proexec2 main.o lib.a
这时候就不用一个一个函数指定了,直接链接静态库,就会生成我们需要的可执行文件proexec2.
共享库和静态库的区别
静态库有一个缺点,当你同时运行多个程序并且他们都使用同一个函数库的函数时,内存就会有多个函数的副本,这会浪费大量的内存资源。而共享库可以解决这种问题。
当一个程序使用共享库时,它的链接方式是这样的:程序本身不包含函数代码,而是引用运行时可访问的共享代码。当编译好的程序被装载到内存执行时,函数引用被解析并产生对共享库的调用,如果有必要,共享库才会被加载到内存中。