windows C/C++移植linux(2) 加载动态共享库的不同

来源:互联网 发布:在哪撤销淘宝物流投诉 编辑:程序博客网 时间:2024/06/04 19:10

windows C/C++移植linux(2) -加载动态共享库的不同

系统动态共享库简介

静态库一个明显的缺点就是,当系统同时运行很多应用程序,并且应用程序都使用来自同一个函数库的函数,那么每一个应用程序都会存在这个函数的多个副本。对于频繁的调用的函数,将会消耗大量的内存和磁盘空间。在linux系统中,每一个程序员用到的静态库至少1M以上,如果机器上运行100个这样的程序,那就占据100M以上内存,磁盘中应用程序假设有2000个,就要接近浪费2G 的空间,在linux系统下/usr/bin就有数千个可执行文件。这种浪费在计算机早期阶段是很严重的问题。
动态共享库的出现解决了这个问题,当程序使用动态库的时候,连接方式是这样:程序本身不包括函数的代码,而是在引用运行时可访问的共享代码。当编译好的程序被装载到内存中执行时,函数引用解析并产生对共享库的调用,必要的时候,共享库才被加载到内存中。这种方法,系统中只会保存共享库的一个副本供很多程序同时使用,磁盘也只有一个副本。
在Windows系统中,动态共享库是以.dll为后缀的文件。在linux系统中,动态共享库是.so后缀的文件。Windows在编程的过程中,.dll文件放到项目文件夹下,然后在IDE下通过界面添加dll文件就可以。在linux系统,修改ld.so.conf文件,或者直接使用rpath命令。在程序中,另一种写法使用动态的调用动态库的方法。在这里,主要介绍linux系统下动态的加载的过程。

平台函数的区别

windows linux LoadLibrary dlopen GetProcAddress dlsys FreeLibrary dlclose

以下函数的介绍从这篇博客中复制而来,这篇博客写的很详细,如果想要进一步了解加载动态库的内容,强烈推荐。

dlopen

1) dlopen
函数原型:void *dlopen(const char *libname,int flag);
功能描述:dlopen必须在dlerror,dlsym和dlclose之前调用,表示要将库装载到内存,准备使用。如果要装载的库依赖于其它库,必须首先装载依赖库。如果dlopen操作失败,返回NULL值;如果库已经被装载过,则dlopen会返回同样的句柄。
参数中的libname一般是库的全路径,这样dlopen会直接装载该文件;如果只是指定了库名称,在dlopen会按照下面的机制去搜寻:
- a.根据环境变量LD_LIBRARY_PATH查找
- b.根据/etc/ld.so.cache查找
- c.查找依次在/lib和/usr/lib目录查找。
flag参数表示处理未定义函数的方式,可以使用RTLD_LAZY或RTLD_NOW。RTLD_LAZY表示暂时不去处理未定义函数,先把库装载到内存,等用到没定义的函数再说;RTLD_NOW表示马上检查是否存在未定义的函数,若存在,则dlopen以失败告终。

dlerror

函数原型:char *dlerror(void);
功能描述:dlerror可以获得最近一次dlopen,dlsym或dlclose操作的错误信息,返回NULL表示无错误。dlerror在返回错误信息的同时,也会清除错误信息。

dlsym

函数原型:void *dlsym(void *handle,const char *symbol);
功能描述:在dlopen之后,库被装载到内存。dlsym可以获得指定函数(symbol)在内存中的位置(指针)。如果找不到指定函数,则dlsym会返回NULL值。但判断函数是否存在最好的方法是使用dlerror函数。

dlclose

函数原型:void *dlsym(void *handle,const char *symbol);
功能描述:在dlopen之后,库被装载到内存。dlsym可以获得指定函数(symbol)在内存中的位置(指针)。如果找不到指定函数,则dlsym会返回NULL值。但判断函数是否存在最好的方法是使用dlerror函数。

例子

在Ubuntu14.04上我们测试一个简单的例子。

  1 // gcc -o dl dl.c -ldl                                                                                                             2 #include <dlfcn.h>  3 #include <stdio.h>  4 int main(int argc, char **argv)  5 {  6     void *handle;  7     double (*mycos)(double);// 函数指针  8     char *error;  9     handle = dlopen("libm.so", RTLD_LAZY); 10     if(!handle) 11     { 12         fprintf(stderr, "%s", dlerror()); 13         return 1; 14     } 15     mycos = dlsym(handle, "cos"); 16     if((error = dlerror()) != NULL) 17     { 18         fprintf(stderr, "%s", error); 19         return 1; 20     } 21     printf("%f:\n", mycos(1.0)); 22     dlclose(handle); 23     return 0; 24  25 }

这个例子是一个简单的加载动态共享库的过程。但是我编译的时候出现了一个错误如下:

dl.cpp:15:29: error: invalid conversion from ‘void*’ todouble (*)(double)’ [-fpermissive]mycos = dlsym(handle, "cos");

后来发现我写的是cpp文件,c语言会隐式转化,将void* 转化为其他类型的指针,但是c++需要显式转化。我习惯写c++代码,后缀就是cpp,然后使用g++编译的时候就出现这种错误了。

写博客是一种好的习惯,把项目的经验教训分享出来,共同进步。不足之处,请多多指教。最后感谢项目中给我提供指导建议的博主。

0 0