C++各种库文件对比.a和.so,.lib和.dll

本文详细介绍了Linux与Windows平台上的静态库(.a/.lib)与动态库(.so/.dll)的区别,包括静态链接的编译流程、动态库的加载机制、隐式与显式调用,以及如何配置动态链接库路径。还提供了ldd工具的使用和ld.so.conf文件的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、两种库

  • Linux下的静态库以.a结尾(Winodws下为.lib)
  • Linux下的动态库以.so 或 .so.y结尾,其中y代表版本号(Windows下为.dll),而且,Linux下的库必须以lib开头,用于系统识别(如:libjpeg.a libsdl.so)

静态库必要的目标代码的是在对程序编译的时候被加入到程序中,而运行时不再需要.a的库了

而动态库,则是在运行时转载所以,动态链接的可执行代码比静态链接的可执行代码小的多

把一个源代码编译成.so:

gcc -shared -o libtry.so try.c

而要生成静态库:

gcc -c try1.c
gcc -c try2.c
ar cqs libtry.a try1.o try2.o(或 ar r libtry.a try1.o try2.o)

库的使用

2、静态库的使用

# gcc -c main.c -o main.o
# gcc main.o -o name -L. -ltry (-l后面的名字就是我们上面生成的try库) 

3、动态库的使用

动态库分为显式调用和隐式调用

3.1、显示调用

需要了解以下几个函数:具体调用可以参考我的上一篇博客
const char *dlerror(void);   
当动态链接库操作函数执行失败时,dlerror可以返回出错信息,为NULL时表示操作函数执行成功。
void *dlopen(const char *filename, int flag);   
成功则返回为void*的句柄。flag可以为RTLD_LAZY(表明在动态链接库的函数代码执行时解决);RTLD_NOW(表明在dlopen返回前就解决所有未定义的符号,一旦未解决,dlopen将返回错误)。filename为动态库路径。

void *dlsym(void *handle, char *symbol);   
dlsym根据动态链接库操作句柄(handle)与符号(实际上就是欲调用的函数名),返回符号对应的函数的执行代码地址。由此地址,可以带参数执行相应的函数。

int dlclose (void *handle);    参数为动态链接库的句柄。    显式调用动态链接库必须包含动态链接库功能接口dlfcn.h(包含dl系列函数的声明)和被调函数的声明。

看起来还比较简单,但是当你对动态链接库函数使用比较频繁的时候,就知道他的麻烦了,所以,不推崇。

3.2、隐式调用

所谓隐式调用,就是调用的时候直接使用动态库中的函数,并不区别对待。
但是在隐式调用的时候必须要让程序能找到你所调用的函数的所属动态库。
我们先来建立一个感性认识:   

# more /etc/ld.so.conf  你会看到以下内容:   

/usr/kerberos/lib    
/usr/X11R6/lib    
/usr/lib/sane    
/usr/lib/qt-3.1/lib    
/usr/lib/mysql    
/usr/lib/qt2/lib    
/usr/local/lib    
/usr/local/BerkeleyDB.4.3/lib

ld.so.conf是系统对动态链接库进行查找的路径配置文件,也就是说该文件是系统链接工具/usr/bin/ld查找动态链接库的地图,所以,要达到我们的目的有以下几种方法:

a.将自己的动态链接库文件拷到以上路径的目录下
    # cp libwx.so.1 /usr/local/lib
b.将自己动态链接库文件的路径加入到该文件中
    # vi /etc/ld.so.conf, 然后加入自己的路径(或pwd >>/etc/ld.so.conf)

    (千万不要将>>写成>,前者是添加,后者是覆盖)
c.把当前路径加入环境变量LD_LIBRARY_PATH,其实就是/usr/bin/ld的环境变量
    # export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH

   
编译的时候:   
# gcc -o try main.c libtry.so.1   
如果没有让/usr/bin/ld知道你的动态链接库在哪,编译的时候就要告诉它:   
# gcc -o try main.c /root/libtry.so.1 ( 或:# gcc -L/root/wx -o qqq main.c libmy.so.1)
-L指定动态链接库所在的目录,有时候用gcc还会碰到-I,-l,他们分别指定头文件的目录和所链接的动态链接库

# ldd try    用来查看可执行文件try的动态链接库的依赖关系

        libjpeg.so.62 => /usr/lib/libjpeg.so.62 (0x00867000)
        libSDL-1.2.so.0 => /usr/lib/libSDL-1.2.so.0 (0x0638a000)
        libc.so.6 => /lib/tls/libc.so.6 (0x0046d000)
        libm.so.6 => /lib/tls/libm.so.6 (0x00598000)
        libdl.so.2 => /lib/libdl.so.2 (0x005bd000)
        libasound.so.2 => /lib/libasound.so.2 (0x062e1000)
        libX11.so.6 => /usr/X11R6/lib/libX11.so.6 (0x005d5000)
        libXext.so.6 => /usr/X11R6/lib/libXext.so.6 (0x0069e000)
        libpthread.so.0 => /lib/tls/libpthread.so.0 (0x006ae000)
        /lib/ld-linux.so.2 (0x00450000)

平常做项目可能不怎么用到这些,不过一定要掌握vs或者qt等IDE里面关于静态库和动态库的导入设置。动态库的显示调用和隐式调用具体分析可以参考我的上一篇博客。

C、传统 C++ #include     //设定插入点 #include      //字符处理 #include      //定义错误码 #include      //浮点数处理 #include     //文件输入/输出 #include     //参数化输入/输出 #include    //数据流输入/输出 #include     //定义各种数据类型最值常量 #include     //定义本地化函数 #include      //定义数学函数 #include      //定义输入/输出函数 #include     //定义杂项函数及内存分配函数 #include     //字符串处理 #include    //基于数组的输入/输出 #include      //定义关于时间的函数 #include      //宽字符处理及输入/输出 #include     //宽字符分类 ////////////////////////////////////////////////////////////////////////// 标准 C++ (同上的不再注释) #include     //STL 通用算法 #include      //STL 位集容器 #include #include #include #include #include      //复数类 #include #include #include #include #include       //STL 双端队列容器 #include     //异常处理类 #include #include    //STL 定义运算函数(代替运算符) #include #include       //STL 线性列表容器 #include        //STL 映射容器 #include #include        //基本输入/输出支持 #include      //输入/输出系统使用的前置声明 #include #include      //基本输入流 #include      //基本输出流 #include       //STL 队列容器 #include        //STL 集合容器 #include      //基于字符串的流 #include       //STL 堆栈容器     #include     //标准异常类 #include     //底层输入/输出支持 #include      //字符串类 #include      //STL 通用模板类 #include      //STL 动态数组容器 #include #include using namespace std; ////////////////////////////////////////////////////////////////////////// C99 增加 #include    //复数处理 #include     //浮点环境 #include   //整数格式转换 #include    //布尔环境 #include    //整型环境 #include    //通用类型数学宏 --------------------------------------------------------------------------------------------------------- 补充: 经常在CSDN以及其他之类的技术论坛上问关于C++文件的问题。提出这些问题的往往就是那些刚学C++的新手。当初我是菜鸟的时候也问过类似的问题。 现在来看看下面两个include: #include // 这个就是1998年标准化以后的标准头文件 #include // 这个就是标准化以前的头文件 更本质上的区别就是iostream把标准C++库的组件放在一个名位std的namespace里面。而相对的iostream.h则将这些标准组件放在全局空间里,同时在标准化以后旧有的C标准库也已经经过改造了。 看看下面这两个头文件 // 标准化后经过改造的C的标准库,所有的组件都放在了std中 #include // 标准化以前C++中的C标准库 #include // 在看看这个头文件C标准库下 基于char* 的字符处理函数库 #include // 在标准化以后他变成了这样 #include // 但是很多朋友还看见过这个字符串处理函数库,他包含了新的string class #include 经过了标准委员会如此大规模手术后,在98年以前出品的C++编译器(BC3.0,BC5.0)上能顺利通过编译的源文件,在支持新标准的编译器上可能无法顺利通过编译也就是很正常的事了。 [起因] 在回过头来看看标准程序库,这个程序库涵盖范围相当广大,提过了许许多多好用的功能。正是因为这样标准程序库中class的名称函数名与第三方提供的程序库中的class名或是函数名发生名字冲突的可能性大大增大。为了避免这个问题的发生,标准委员会决定将标准程序库中每一样东西都放在namespace std中。但是这么做同时有引来了一个新的问题。很多C++程序代码依赖那些已经存在很多年的C++ “准”标准程序库(C++迟迟未标准化才导致这些情况的发生),例如iosteam.h,complex.h等等。 为了解决这个新出现的问题,标准化委员会决定设计一些新的头文件名,给那些穿上std外衣的组件所使用。把C++文件.h去掉,于是就有前面出现的iostream,同样C的头文件也做了相同的处理,同时在前面加上了一个字母c,以表示是C的头文件(感觉上有中种族歧视的感觉)。同时标准化委员会声明就有的C++文件将不再列于被支持的名单之中了,而旧有的C头文件为了满足“对C的兼容性”这个古老契约,仍然将继续存活下去。 但是,那些编译器厂商不可能去推翻他们客户的旧有编译器(也跟本不会去这么做),所以那些旧有的C++文件仍然苟延残喘的活了下来,并不断的扰乱那些C++新兵的心智。 下面就是现在大多数C++开发工具表示头文件的组织状态: 1. 旧的C++文件 比如iostream.h,他们虽然被标准化委员会所抛弃,但由于各大厂商为了各自的商业利益仍然将继续存活下去,这些头文件的内容将不处于namespace std中。 2. 新的C++文件如iostream虽然提供了旧有头文件相同的功能,但他的内容都并入了namespace std中,从而有效避免了名字污染的问题。 3. 标准C的头文件如stdio.h继续获得支持,这类文件的内容并未放在std中。 4. C函数库的技能也有对应的新式C++版本,起名称类似cstdio,这类头文件的内容也有幸穿上了std的外衣。 其实标准化以后的标准程序库的改动并不只有这些而已,很多的标准化组件都被“tamplate化”。其中就有元老级人物iostream。标准程序库的问题并不是用一篇,两篇文章就可以说清楚的。如果你像进一步的了解C++的标准程序库的话,你可以看看侯先生的《C++标准程序库》。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值