我们在编写一个C语言程序的时候,经常会遇到好多重复或常用的部分,如果每次都重新编写固然是可以的,不过那样会大大降低工作效率,并且影响代码的可读性,更不利于后期的代码维护。我们可以把他们制作成相应的功能函数,使用时直接调用就会很方便,还可以进行后期的功能升级。
例如我要在一段代码中多次交换两个变量的值,我可以在代码中多次写入
i=x;
x=y;
y=i;
不过这样未免有点麻烦我们可以编写一个change_two_int()函数进行简化。
定义如下函数:
void change_two_int(int *a,int *b)
{
int c;
c=*a;
*a=*b;
*b=c;
}
这样每次要进行交换时只需调用 change_two_int(&x , &y);即可,是否方便了许多?
那么我们要讨论的和这些有什么关系呢?库通俗的说就是把这些常用函数的目标文件打包在一起,提供相应函数的接口,便于程序员使用。库是别人写好的现有的,成熟的,可以复用的代码,我们只需要知道其接口如何定义,便可以自如使用。
现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。比如我们常使用的printf函数,就是c标准库提供的函数。我们在使用时只需要包含相应的头文件就可以使用(非静态编译还要有相应的库文件)。而不用关心printf函数具体是如何实现的,这样就大大提高了程序员编写代码的效率。从使用方法上分库大体上可以分为两类:静态库和共享库。在windows中静态库是以 .lib 为后缀的文件,共享库是以 .dll 为后缀的文件。在linux中静态库是以 .a 为后缀的文件,共享库是以 .so为后缀的文件。
以linux下的静态库和动态库为例我们研究一下,首先我们看一下他们的生成方式
静态库:
首先将源文件编译成目标文件:gcc –c a.c b.c
生成静态库:ar –rc libstatic.a a.o b.o
共享库:
同静态库一样编译成目标文件:gcc –c a.c b.c
生成共享库:gcc –fPIC –shared –o libshared.so a.o b.o
由此可见静态库和动态库都是对目标文件的处理,也可以说库文件已经是机器码文件了,静态库和共享库的加载过程有很大的区别。
静态库的链接方法:
gcc –o staticcode –L. –lstatic main.c –static(默认库在当前文件夹)
共享库的链接方法:
gcc –o sharedcode -L. –lshared main.c(默认库在当前文件夹)
当程序与静态库连接时,库中目标文件所含的所有将被程序使用的函数的机器码被copy到最终的可执行文件中。这就会导致最终生成的可执行代码量相对变多,相当于编译器将代码补充完整了,这样运行起来相对就快些。不过会有个缺点: 占用磁盘和内存空间. 静态库会被添加到和它连接的每个程序中, 而且这些程序运行时, 都会被加载到内存中. 无形中又多消耗了更多的内存空间.
与共享库连接的可执行文件只包含它需要的函数的引用表,而不是所有的函数代码,只有在程序执行时, 那些需要的函数代码才被拷贝到内存中。这样就使可执行文件比较小, 节省磁盘空间,更进一步,操作系统使用虚拟内存,使得一份共享库驻留在内存中被多个程序使用,也同时节约了内存。不过由于运行时要去链接库会花费一定的时间,执行速度相对会慢一些,总的来说静态库是牺牲了空间效率,换取了时间效率,共享库是牺牲了时间效率换取了空间效率,没有好与坏的区别,只看具体需要了。
另外,.一个程序编好后,有时需要做一些修改和优化,如果我们要修改的刚好是库函数的话,在接口不变的前提下,使用共享库的程序只需要将共享库重新编译就可以了,而使用静态库的程序则需要将静态库重新编译好后,将程序再重新编译一便。
库操作的相关命令
nm
功能:
列出编入目标文件或二进制文件的所有符号。用途一:查看程序调用什么函数;用 途二:查看一个给定的库或目标文件是否提供了所需的函数。
语法:nm [options] file
常用选项:
-C 将符号名转换为用户级的名字。在让C++函数名可读方面特别有用。
-s 当用于.a文件时,输出把符号名映射到定义该符号的模块或成员名的索引。
-u 只显示未定义的符号,即在被检查的文件外部定义的文件。
-l 使用调试信息输出定义每个符号的行号,或未定义符号的重要位项。
ar
功能:将多个.o文件组合到一起成为.a文件。
语法:ar [options] lib*.a *.o
常用选项:
-c 如果存档文件不存在,则创建,并不显示ar发出的警告。
-q 把*.o添加到存档文件末尾而不检查是否进行替换。
-r 向存档文件中插入.o文件,替换已有的任何同名文件,新成员添加到文档末尾。
-s 创建或升级从符号到.a文件之间的交叉索引映射表,并加入到.a文件中。
等价与ranlib [*.a]。执行该命令后,可用nm –s来查看生成的索引。
ldd
功能:显示可执行程序运行所需的共享库。
语法
ldd [options] file
常用选项:
-d 执行重定位并报告所有丢失的函数。
-r 执行对函数和数据对象的重定位并报告丢失的任何函数或数据对象。
ldconfig
功能:
在默认搜寻目录(/lib和/usr/lib)及动态库配置文件/etc/ld.so.conf中所列的目录下,搜索出可共享的动态链接库(lib*.so*),进而创建出动态装入程序(ld.so)所需的连接和缓存文件。缓存文件默认为 /etc/ld.so.cache,此文件保存了已排好序的动态链接库名字列表。该在系统启动时会运行,而当用户安装了一个新的动态链接库时,就需要手工运行这个命令。
语法:
ldconfig [options] path
例如:ldconfig /root/lib 让系统共享/root/lib目录下的动态链接库,即在/etc/ld.so.cache中添加指定目录下的共享库。[注意]若该目录不在/lib,/usr/lib,/etc/ld.soconf所列的目录列表里,则再次运行ldconf时,此目录下的动态链接库就不被系统共享了。
常用选项:
-v 更新/etc/ld.so.cache的内容,列处每个库的版本号,扫描的目录和所有创建和更新的链接。
-p 仅显示/etc/ld.so.cache的内容,即ld.so所知道的共享库的当前列表。
-n ldconf仅扫描-n命令所指定的目录
-f CONF 指定动态链接库的配置文件为CONF,系统默认为/etc/ld.so.conf。
-c CACHE 指定生成的缓存文件为CACHE,系统默认为/etc/ld.so.cache。
当ldconf不带选项时,仅更新高速缓冲文件。
环境变量
$LD_PRELOAD 由空格分隔的共享库列表,在其它库之前加载,使它们有机会覆盖或重新定义标准库。
$LD_LIBRARY_PATH 由冒号分隔的目录清单,都是共享库搜索时会访问的目录。
我们在编写一个C语言程序的时候,经常会遇到好多重复或常用的部分,如果每次都重新编写固然是可以的,不过那样会大大降低工作效率,并且影响代码的可读性,更不利于后期的代码维护。我们可以把他们制作成相应的功能函数,使用时直接调用就会很方便,还可以进行后期的功能升级。
例如我要在一段代码中多次交换两个变量的值,我可以在代码中多次写入
i=x;
x=y;
y=i;
不过这样未免有点麻烦我们可以编写一个change_two_int()函数进行简化。
定义如下函数:
void change_two_int(int *a,int *b)
{
int c;
c=*a;
*a=*b;
*b=c;
}
这样每次要进行交换时只需调用 change_two_int(&x , &y);即可,是否方便了许多?
那么我们要讨论的和这些有什么关系呢?库通俗的说就是把这些常用函数的目标文件打包在一起,提供相应函数的接口,便于程序员使用。库是别人写好的现有的,成熟的,可以复用的代码,我们只需要知道其接口如何定义,便可以自如使用。
现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。比如我们常使用的printf函数,就是c标准库提供的函数。我们在使用时只需要包含相应的头文件就可以使用(非静态编译还要有相应的库文件)。而不用关心printf函数具体是如何实现的,这样就大大提高了程序员编写代码的效率。从使用方法上分库大体上可以分为两类:静态库和共享库。在windows中静态库是以 .lib 为后缀的文件,共享库是以 .dll 为后缀的文件。在linux中静态库是以 .a 为后缀的文件,共享库是以 .so为后缀的文件。
以linux下的静态库和动态库为例我们研究一下,首先我们看一下他们的生成方式
静态库:
首先将源文件编译成目标文件:gcc –c a.c b.c
生成静态库:ar –rc libstatic.a a.o b.o
共享库:
同静态库一样编译成目标文件:gcc –c a.c b.c
生成共享库:gcc –fPIC –shared –o libshared.so a.o b.o
由此可见静态库和动态库都是对目标文件的处理,也可以说库文件已经是机器码文件了,静态库和共享库的加载过程有很大的区别。
静态库的链接方法:
gcc –o staticcode –L. –lstatic main.c –static(默认库在当前文件夹)
共享库的链接方法:
gcc –o sharedcode -L. –lshared main.c(默认库在当前文件夹)
当程序与静态库连接时,库中目标文件所含的所有将被程序使用的函数的机器码被copy到最终的可执行文件中。这就会导致最终生成的可执行代码量相对变多,相当于编译器将代码补充完整了,这样运行起来相对就快些。不过会有个缺点: 占用磁盘和内存空间. 静态库会被添加到和它连接的每个程序中, 而且这些程序运行时, 都会被加载到内存中. 无形中又多消耗了更多的内存空间.
与共享库连接的可执行文件只包含它需要的函数的引用表,而不是所有的函数代码,只有在程序执行时, 那些需要的函数代码才被拷贝到内存中。这样就使可执行文件比较小, 节省磁盘空间,更进一步,操作系统使用虚拟内存,使得一份共享库驻留在内存中被多个程序使用,也同时节约了内存。不过由于运行时要去链接库会花费一定的时间,执行速度相对会慢一些,总的来说静态库是牺牲了空间效率,换取了时间效率,共享库是牺牲了时间效率换取了空间效率,没有好与坏的区别,只看具体需要了。
另外,.一个程序编好后,有时需要做一些修改和优化,如果我们要修改的刚好是库函数的话,在接口不变的前提下,使用共享库的程序只需要将共享库重新编译就可以了,而使用静态库的程序则需要将静态库重新编译好后,将程序再重新编译一便。
分享到:
相关推荐
详细讲解C语言动态静态链接库的概念,创建方法,使用方法,例子简单易懂
动态库的制作: 方法一: gcc -c -fPIC add.c sub.c div.c mul.c //-c表示生成.o目标文件,-f后加一些编译选项,PIC表示与位置无关 gcc -shared -o libmymath.so add.o sub.o mul.o div....
1. 工程中包含静态库A,动态库B,可执行程序C。C依赖于A和B,而B依赖于A。在A中定义有全局变量X(或类的静态成员变量),则在动态库B中访问的X,与可执行程序C中访问的X是同一个变量还是两个不同的变量? 答案:是两...
动态库的制作: 方法一: gcc -c -fPIC add.c sub.c div.c mul.c //-c表示生成.o目标文件,-f后加一些编译选项,PIC表示与位置无关 gcc -shared -o libmymath.so add.o sub.o mul.o div.o//创建共享库mymath,添加...
Linux下Gcc生成和使用静态库和动态库详解Linux下Gcc生成和使用静态库和动态库详解
rust代码与c代码相互调用,rust调用c动态库静态库,以及rust代码之间的相互引用
静态库 与 动态库 的联系与区别
linux下C语言,通过gcc生成静态库和动态库
多种输出,包括动态文件、静态文件、stdout、stderr、syslog 可以在运行时动态刷新配置,只需要调用函数zlog_reload() 高性能,在我的笔记本上达到72'000条日志每秒, 大概是syslog(3)配合rsyslogd的200倍速度 用户...
本书主要写得是动态库与静态库,有助于更深层次的学习C语言
C与C++接口、静态库、动态库的互调。使用build.sh脚本方式编译,直接运行main程序即可。
根据使用库函数时,函数库加载时机的差异,将函数库分为静态函数库和动态函数库,具体差异是:C语言程序如果使用静态函数库的函数,那么整个函数库的代码都会和C语言程序一起编译成可执行代码,程序的体积会膨胀;...
\在C语言中,全局变量分配在内存中的静态存储区,非静态的局部变量(包括形参)是分配在内存的动态存储区,该存储区被称为栈。除此之外,c语言还允许建立内存动态分配区域,以存放一些临时用的数据,这些数据不必
linux系统编程-静态库-动态库的制作-gdb调试常见段错误-c语言实现
>>>>>>老生常谈C语言接静态函数库的制作和使用>>点击进入 2 动态函数库的制作和使用 动态函数库的制作步骤可以用下图来描述,具体包括 (1) 编写函数的.c文件(例如add.c、sub.c、mul.c和div.c) (2) 编写Makefile,...
用于C/c++c,构建在C语言之上,进行图形化界面处理的蛋蛋库。分静态及动态的界面代码。
第 5 章 预处理、动态库、静态库 第 6 章 指针 第 7 章 动态内存申请 第 8 章 字符串处理函数 第 9 章 结构体 第 10 章 链表 第 11 章 文件 第 12 章 Makefile 自用的千锋讲义文档,涵盖了C语言的各种语法、...
本文件包含了android交叉 编译的h265 .so动态库 .a静态库,还有头文件。 亲测可用。
C语言libuv-1.42.0源码,C语言实现的事件驱动,可以编译动态库或静态库使用,而且很多开源项目也会用到该库,比如netdata