35.静态链接库和动态链接库


35.1.函数库的前世今生
(1)函数库就是一些事先写好的函数的集合,因为函数是模块化的,因此可以被复用;我们写好了某个函数,可以被反复使用,譬如A写好了某个函数然后共享出来,当B有相同的需求时就不需自己写直接用A写好的这个函数即可。
(2)最开始是没有函数库的,每个人写程序都要从零开始自己写,时间长了慢慢的早期的程序员就积累下来了一些有用的函数;早期的程序员经常参加行业聚会,在聚会上大家互相交换各自的函数库;后来程序员中的一些大神就提出把大家各自的函数库收拢在一起,然后经过校准和整理,最后形成了一份标准化的函数库,就是现在的标准的函数库,譬如说glibc。
(3)早期的函数共享都是以源代码的形式进行的,该方式共享是最彻底的(后来这种源码共享的方向就形成了我们现在的开源社区),但该方式的缺点就是无法以商业化形式来发布函数库;商业公司需要将自己的有用的函数库共享给别人(当然是付费的),但又不能给客户源代码,则解决方案就是以库(静态库和动态库)的形式来提供。


35.2.静态库和动态库
(1)较早出现的是静态链接库,静态库其实就是商业公司将自己的函数库源代码经过只编译不链接形成.o的目标文件,然后用ar工具将.o文件归档成.a的归档文件(.a的归档文件又叫静态链接库文件);商业公司通过发布.a库文件和.h头文件来提供静态库给客户使用;客户拿到.a和.h文件后,通过.h头文件得知库中的库函数的原型,然后在自己的.c文件中直接调用这些库文件,在链接的时候链接器会去.a文件中拿出被调用的函数的编译后的.o二进制代码段链接进去形成最终的可执行程序;静态库在用户链接自己的可执行程序时就已经把调用的库中的函数的代码段链接进最终可执行程序中了,该方式的优点是可以独立执行,缺点是程序太过庞大,尤其是有多个应用程序都使用了该库函数时,实际上在多个应用程序最后生成的可执行程序中都各自有1份该库函数的代码段,当这些应用程序同时在内存中运行时,实际上在内存中有多个该库函数的代码段,导致重复加载。
(2)动态链接库出现较晚,效率更高一些,现在我们一般都是使用动态库;动态链接库本身不将库函数的代码段链接入可执行程序,只是做个标记,然后当应用程序在内存中执行时,运行时环境发现它调用了某个动态库中的库函数时,会去加载这个动态库到内存中,以后不管有多少个应用程序去调用该库中的函数都会跳转到第1次加载的地方去执行,不会重复加载。
(3)gcc中编译链接程序默认是使用动态库的,要想使用静态链接需要显式用-static来强制静态链接;调用库函数时应包含相应的头文件;调用库函数时需注意函数原型;有些库函数链接时需要额外用-lxxx来指定链接(譬如数学库和线程库);如果使用动态库要注意-L指定动态库的地址。


35.3.字符串库函数
(1)字符串就是由多个字符在内存中连续分布组成的字符结构,字符串的特点是指定了开头(字符串的指针)和结尾(结尾固定为字符’\0’),而没有指定长度(长度由开头地址和结尾地址相减得到)。
(2)因为字符串处理的需求是客观的,所以从很早开始人们就在写很多关于字符串处理的函数,然后逐渐形成了现在的字符串处理函数库;面试笔试时,常用字符串处理函数也是经常考到的点。
(3)C库中字符串处理函数包含在string.h中,该文件在ubuntu系统位于/usr/include目录中,在学习字符串处理函数时可参照string.h文件和man手册及网上的博客针对常用的字符串口处理函数进行针对性的学习和总结,这样能在很大程度上提高编程能力。
(4)常见字符串处理函数memcpy(确定src和dst不会overlap,则使用memcpy效率高)、memmove(确定会overlap或者不确定但是有可能overlap,则使用memove比较保险)、memset、memcmp、memchr、strcpy、strncpy、strcat、strncat、strcmp、strncmp、strdup、strndup、strchr、strstr、strtok。


35.4.数学库函数
(1)使用数学库函数的时候,只需要包含math.h即可;真正的数学运算的函数定义在/usr/include/i386-linux-gnu/bits/mathcalls.h中。
(2)计算开平方时使用库函数double sqrt(double x);在编译后需注意区分编译时警告/错误及链接时的错误;4.6.10.math.c:9:13: warning: incompatible implicit declaration of built-in function ‘sqrt’ [enabled by default](编译时警告/错误);double b = sqrt(a);;4.6.10.math.c:(.text+0x1b): undefined reference to `sqrt’ collect2: error: ld returned 1 exit status(链接时错误,sqrt函数有声明(声明就在math.h中)有引用(在math.c)但是没有定义,链接器找不到函数体;sqrt本来是库函数,在编译器库中是有.a和.so链接库的(函数体在链接库中的))。
(3)C链接器的工作特点,因为库函数有很多,链接器去库函数目录搜索的时间比较久,为了提升速度采用了折中的方案;链接器只是默认的寻找几个最常用的库,如果是一些不常用的库中的函数被调用,需要程序员在链接时明确给出要扩展查找的库的名字;链接时可以用-lxxx来指示链接器去到libxxx.so中去查找这个函数。
(4)链接时加-lm即告诉链接器到libm中去查找用到的函数;实战中发现在高版本的gcc中,经常会出现没加-lm也可以编译链接的;我们可使用ldd命令查看可执行程序链接使用到的库的路径(ldd a.out)。


35.5.自己制作静态链接库并使用
(1)自己制作静态链接库;首先使用gcc -c只编译不连接(gcc rston.c -o rston.o -c),生成.o文件;然后使用ar工具打包成.a归档文件(ar -rc librston.a rston.o);库名不能随便乱起,一般是lib+库名称(librston);后缀名是.a表示是1个归档文件(librston.a);制作出静态库之后,发布时需要发布.a文件和.h文件。
(2)使用静态链接库;把.a和.h都放在某个目录中,然后在.c文件中包含库的.h,然后直接使用库函数;第1次编译方法(gcc testlib.c -o testlib)+报错信息testlib.c:(.text+0x19): undefined reference to `add’+collect2: ld returned 1 exit status;第2次编译方法(gcc testlib.c -o testlib -lrston)+报错信息/usr/bin/ld: cannot find -lrston+collect2: ld returned 1 exit status;第3次编译方法(gcc testlib.c -o testlib -lrston -L.)+无报错,生成testlib,执行正确。
(3)ar命令和nm命令,除了ar归档命令外,还有个nm命令也很有用,它可以用来查看某个.a文件中都有哪些符号。


35.6.自己制作动态链接库并使用
(1)自己制作动态链接库动;动态链接库的后缀名是.so(对应windows系统中的dll),静态链接库的扩展名是.a;首先使用gcc -c只编译不连接(gcc rston.c -o rston.o -c -FPIC;-fPIC是位置无关码),生成.o文件;然后使用gcc工具打包成.so文件(gcc rston.o -o librston.so -shared;-shared是按照共享库的方式来链接);制作成动态库后,发布时需发布.so文件和.h文件。
(2)使用动态链接库;第1次编译方法(gcc testlib.c -o testlib)+报错信息testlib.c:(.text+0x19): undefined reference to `add’+collect2: ld returned 1 exit status;第2次编译方法(gcc testlib.c -o testlib -lrston)+报错信息/usr/bin/ld: cannot find -lrston+collect2: ld returned 1 exit status;第3次编译方法(gcc testlib.c -o testlib -lrston -L.)+无报错,生成testlib,执行错误。
(3)执行报错信息(error while loading shared libraries: librston.so: cannot open shared object file: No such file or directory);错误原因是动态链接库运行时需要被加载(运行时环境在执行testlib程序的时候发现其动态链接了librston.so,于是乎会去固定目录尝试加载libaston.so,如果加载失败则会打印以上错误信息)。
(4)解决方法1是将librston.so放到固定目录下即可,该固定目录一般是/usr/lib目录(sudo cp librston.so /usr/lib);解决方法2是将libaston.so所在的目录导出

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值