目录

 



文章目录


 

C 语言的库

C 语言的库有两种,静态链接库和动态链接库。在 Linux 中,静态链接库命名为 lib*.a,动态库为 lib*.so。这些库文件存在的价值就是抽象出通用的函数,避免重复造轮子。不管是使用哪一种库,程序员必须在程序中通过 include 来包含相应的头文件,并在预编译阶段替换 include 的内容,然后在链接阶段将调用到的库函数从各自所在的档案库中链接到合适的地方。

C 语言编程 — 静态链接库和动态链接库_库文件

静态链接库

静态链接,即:在链接阶段,将源文件中用到的库函数与汇编生成的 .o 目标文件 合并生成 可执行文件。所以,静态链接方式的好处是:方便程序移植,因为可执行程序包含了所有库函数的内容,放在任何环境当中都可以执行。缺点就是:可执行文件通常会比较大。而且每次库文件升级的话,都要重新编译源文件,很不方便。

直观的看,一个全静态方式生成的简单 print 程序大小为 857K,而动态链接生成的一样的可执行文件只有 8.4K,因为静态链接的可执行文件包含了整理 stdio 库文件。

C 语言编程 — 静态链接库和动态链接库_动态链接_02

如上图,对于静态编译的程序 1、2,因为都使用了 staticMath 库。所以在内存中就有两份相同的 staticMath.o 目标文件,一旦程序数量过多就很可能会内存不足,很浪费空间。

生成静态链接库

  • add.c
#include "add.h"

int add(int a, int b) {
return a + b;
}


  • add.h
#ifndef _ADD_H
#define _ADD_H

int add(int a, int b);

#endif


  • 生成目标文件
gcc -c add.c --std c99


  • 生成静态链接库文件
ar -crv libadd.a add.o


使用静态链接库:

  1. include
#include <stdio.h>

#include "./add.h"


int main() {
int number1 = 10;
int number2 = 90;
printf("SUM: %d\n", add(number1, number2));
return 0;
}


  1. 编译
gcc -std=c99 test.c -o test -L./ -ladd


  • -L:指定加载库文件的路径。
  • -l:指定加载的库文件。
动态链接库

动态链接,即:在程序运行过程中动态的调用库文件。好处是:占空间小、程序文件小。缺点是:可移植性太差,如果两台电脑运行环境不同,例如:动态库存放的位置不一样、没有动态库文件,就很可能导致程序运行失败。

C 语言编程 — 静态链接库和动态链接库_动态链接库_03

生成动态链接库

  • 生成目标文件
gcc -c add.c --std c99


  • 生成动态链接库文件
  • -shared :指定生成动态链接库。
  • -fPIC :表示编译为位置独立的代码,用于编译共享库。目标文件需要创建成位置无关码,就是在可执行程序装载它们的时候,它们可以放在可执行程序的内存里的任何地方。
gcc -fPIC -shared -o libadd.so add.c


  • 编译并动态链接库文件
gcc -std=c99 test.c -o test -L./ -ladd


  • 执行程序
$ ./test
./test: error while loading shared libraries: libadd.so: cannot open shared object file: No such file or directory


ERR:libadd.so: cannot open shared object file: No such file or directory

因为执行程序找不到 libadd.so,查看 test 程序的动态链接库信息:

$ ldd test
linux-vdso.so.1 => (0x00007fff39fd5000)
libadd.so => not found
libc.so.6 => /lib64/libc.so.6 (0x00007f5410c0b000)
/lib64/ld-linux-x86-64.so.2 (0x00007f5410fd9000)


可以看到 test 执行程序用到的 libadd.so 确实是 not found,这是因为在 /etc/ld.so.conf 文件中设置了动态链接库了寻找路径:

$ cat /etc/ld.so.conf
include ld.so.conf.d/*.conf

$ ll /etc/ld.so.conf.d
总用量 40
-rw-r--r-- 1 root root 26 4月 7 22:41 bind-export-x86_64.conf
-rw-r--r-- 1 root root 24 4月 2 02:32 hcoll.conf
-rw-r--r-- 1 root root 19 4月 2 02:23 ibutils.conf
-r--r--r-- 1 root root 63 4月 1 07:40 kernel-3.10.0-1127.el7.x86_64.conf
-r--r--r--. 1 root root 63 10月 21 2017 kernel-3.10.0-693.5.2.el7.x86_64.conf
-r--r--r-- 1 root root 63 11月 29 2018 kernel-3.10.0-957.1.3.el7.x86_64.conf
-r--r--r-- 1 root root 63 5月 1 22:57 kernel-rt-3.10.0-1127.rt56.1093.el7.x86_64.conf
-rw-r--r-- 1 root root 17 4月 3 01:52 mariadb-x86_64.conf
-rw-r--r-- 1 root root 22 4月 2 02:26 mxm.conf
-rw-r--r-- 1 root root 24 4月 2 02:28 sharp.conf


显然这里是没有 libadd.so 的存储路径的,所以我们需要添加一下 libadd.so 的路径:

$ cat /etc/ld.so.conf.d/test.conf
/root/workspace/test


然后执行 ldconfig 命令生效,再次执行 test 程序:

$ ./test
SUM: 100


总结

综上说述,静态和动态链接库的选择要视情况而定。通常推荐动态链接方式,因为可以很好的节约内存,而且方便后续库文件的升级。