静态调用和动态调用动态库区别

为什么要设计出来两种调用方式?
静态不是很好吗?
直接就调用了。

动态还要dlopen dlclose一系列额外的动作。

---------------------------------------------------------------------------------------------------------

随便举个例子,我将不同语言的资源封装在dll中,有 中文.dll、english.dll、……
我软件运行时可以通过配置文件,或用户菜单更改需要载入的dll
而如果是静态调用的话,就得为每一种语言修改代码重新编译了

第二点,如果是动态调用,只要保证接口不变,dll内容是可以修改的
而如果是静态调用的话,修改了dll内容,就得将所有用到它的宿主程序重新编译

第三点,如果是静态调用的话,dll必须放在指定的几个搜索目录中
而如果是动态调用的话,可以在dlopen参数中指定一个具体的目录


------------------------------------------------------------------------------------

动态库的显式调用

库函数dlopen()将打开一个新库,并把它装入内存。该函数主要用来加载库中的符号,这些符号在编译的时候是不知道的。比如Apache Web服务器利用这个函数在运行过程中加载模块,这为它提供了额外的能力。一个配置文件控制了加载模块的过程。这种机制使得在系统中添加或者删除一个模块时,都不需要重新编译了。


dlopen()dlfcn.h中定义,并在dl库中实现。它需要两个参数:一个文件名和一个标志。文件名可以是我们学习过的库名字。标志指明是否立刻计算库的依赖性。如果设置为RTLD_NOW的话,则立刻计算;如果设置的是RTLD_LAZY,则在需要的时候才计算。另外,可以指定RTLD_GLOBAL,它使得那些在以后才加载的库可以获得其中的符号。


当库被装入后,可以把 dlopen()返回的句柄作为给 dlsym()的第一个参数,以获得符号在库中的地址。使用这个地址,就可以获得库中特定函数的指针,并且调用装载库中的相应函数。


下面详细说明一下这些函数。

  • dlerror

原型为:const char *dlerror(void);

当动态链接库操作函数执行失败时,dlerror可以返回出错信息,返回值为NULL时表示操作函数执行成功。

  • dlopen

原型为:void *dlopen (const char *filename, int flag);

dlopen用于打开指定名字(filename)的动态链接库,并返回操作句柄。

filename:如果名字不以/开头,则非绝对路径名,将按下列先后顺序查找该文件。

(1)用户环境变量中的LD_LIBRARY值;

(2)动态链接缓冲文件/etc/ld.so.cache

(3)目录/lib/usr/lib

flag表示在什么时候解决未定义的符号(调用)。取值有两个:

1)RTLD_LAZY :表明在动态链接库的函数代码执行时解决。

2)RTLD_NOW :表明在dlopen返回前就解决所有未定义的符号,一旦未解决,dlopen将返回错误。

dlopen调用失败时,将返回NULL值,否则返回的是操作句柄。

  • dlsym

取函数执行地址

原型为:void *dlsym(void *handle, char *symbol);

dlsym根据动态链接库操作句柄(handle)与符号(symbol),返回符号对应的函数的执行代码地址。由此地址,可以带参数执行相应的函数。

如程序代码:void (*add)(int x,int y); /*说明一下要调用的动态函数add*/

add=dlsym("xxx.so","add");/*打开xxx.so共享库,add函数地址*/

add(89,369);/*带两个参数89369调用add函数*/

  • dlclose:关闭动态链接库

原型为:int dlclose (void *handle);

dlclose用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为0,才会真正被系统卸载。





隐式链接是指在代码中使用了了库中的代码,只是在链接时,链接器会把该库的符号信息以及导入函数的信息写入到生成的Exe文件的特定的区段中。当该程序加载时,操作系统会根据这个区段中的信息,来查找每个它需要的动态库,并根据这些动态库的导出表,与程序中的导入表相配对,以确定程序中使用的动态库中的代码在什么位置。这样应用程序就能够正确是链接到动态库中的代码了。如果在这个过程中,发生了错误,比如没有找到要求的库文件,或者库中没有你要使用的函数,程序的初始化就会失败,操作系统就会报错,并终止该程序的初始化,你的程序就死掉了。 
显式链接一般是指在程序运行中,由程序代码用LoadLibrary和LoadLibraryEx函数来加载动态库。这两个函数仅仅是把库文件映射到你的进程地址空间中,并不会查找你要使用的函数的地址。如果这些函数成功,就会返回库文件在你的进程中的映像的基址,随便你就可以使用这个基址来调用GetProcAddress()函数来得到你要用的库中的函数的地址了。如果LoadLibrary函数失败,就会返回NULL,并不会强制杀死你的应用程序。 
两种方法对于你的程序调用动态库时没有任何区别,只是你在编程时,步骤是不一样的。显式调用麻烦了点,但可以没有相应的lib库;隐式调用,使用起来比较简单,有函数的声明就可以了,但必须有lib库。

在VC中两种方式的具体方法: 
一、动态库的隐示调用: 
在 VC 工程中直接链接静态输入库XXX.lib,然后即可像调用其它源文件中 
的函数一样调用DLL中的函数了。 
二、动态库的显式调用: 
显式调用动态库步骤: 
1、创建一个函数指针,其指针数据类型要与调用的 DLL 引出函数相吻 
合。 
2、通过 Win32 API 函数LoadLibrary()显式的调用DLL,此函数返回 
DLL 的实例句柄。 
3、通过 Win32 API 函数GetProcAddress()获取要调用的DLL 的函数地 
址,把结果赋给自定义函数的指针类型。 
4、使用函数指针来调用 DLL 函数。 
5、最后调用完成后,通过 Win32 API 函数FreeLibrary()释放DLL 函数。





1. 用 c 语言写动态库:

/*

  * libsthc.h

  * Declarations for function add

  */

#include "stdio.h"

#include "stdlib.h"

#include "stdarg.h"

 

#ifdef __cplusplus

extern "C"

{

#endif

int add(int x, int y);

 

#ifdef __cplusplus

}

#endif

 

/*

  * libsthc.c

  * Implementation of function add declared in libsthc.h

  * in c language

  */

#include "libsthc.h"

 

int add(int x, int y)

{

         return x + y;

}

 

#makefile

libsthc.so:libsthc.o

         gcc -shared libsthc.o -lc -o libsthc.so

libsthc.o:libsthc.c libsthc.h

         gcc -fPIC -c libsthc.c -o libsthc.o

all:libsthc.so

clean:

         rm -f *.o *.so

 

make 完成后,会生成一个动态库,即 libsthc.so 。为了使其他程序也可以使用该动态库,需要将库文件 libsthc.so 拷贝到 /usr/lib目录下 ( 由于权限的问题,一般要以 root 的身分进行拷贝 ) ,为了使其他程序也可以使用该动态库,需要将头文件 libsthc.h 拷贝到 /usr/include 目录下 ( 由于权限的问题 , 一般要以 root 的身分进行拷贝 ) 。

 

1.1 用 c 语言静态方式调用动态库 libsthc.so :

/*

  * ctest.c

  * Testing program for libsthc.so library

  * in c languange

  * by 玄机逸士

*/

#include "libsthc.h"

int main(void)

{

         printf("%d/n", add(1, 2));

         return 0;

}

 

#makefile:

ctest:ctest.o

         gcc ctest.o -lsthc -o ctest

ctest.o:ctest.c

         gcc -c ctest.c -o ctest.o

all:ctest

clean:

         rm -f *.o ctest

 

1.2 用 c 语言动态方式调用动态库 libsthc.so :

/*cdltest.c*/

#include "stdio.h"

#include "stdlib.h"

#include "dlfcn.h"

 

int main(void)

{

         void *handle;

         int (*fcn)(int x, int y);

         const char *errmsg;

        

         /* open the library */

         handle = dlopen("libsthc.so", RTLD_NOW);

         if(handle == NULL)

         {

                   fprintf(stderr, "Failed to load libsthc.so: %s/n", dlerror());

                   return 1;

         }

         dlerror();

 

         //*(void **)(&fcn) = dlsym(handle, "add");            //ok

         fcn = dlsym(handle, "add");                                   //ok

         if((errmsg = dlerror()) != NULL)

         {

                   printf("%s/n", errmsg);

                  return 1;

         }

         printf("%d/n", fcn(1, 5));

        

         dlclose(handle);

         return 0;

}

 

#makefile :

cdltest:cdltest.o

         gcc cdltest.o -ldl -lsthc -o cdltest

cdltest.o:cdltest.c

         gcc -c cdltest.c -o cdltest.o

all:cdltest

clean:

         rm -f *.o cdltest

 

1.3 用 c++ 静态方式调用动态库 libsthc.so :

/*cpptest.cc*/

#include "libsthc.h"

using namespace std;

int main(void)

{

         printf("%d/n", add(1, 2));

         return 0;

}

 

#makefile:

cpptest:cpptest.o

         g++ cpptest.o –o cpptest -lsthc

cpptest.o:cpptest.cc

         g++ -c cpptest.cc -Wno-deprecated -o cpptest.o

all:cpptest

clean:

         rm -f *.o cpptest

 

1.4 用 c++ 动态方式调用动态库 libsthc.so :

/*cppdltest.cpp*/

#include "stdio.h"

#include "stdlib.h"

#include "dlfcn.h"

 

int main(void)

{

         void *handle;

         int (*fcn)(int x, int y);

         const char *errmsg;

        

         /* open the library */

         handle = dlopen("libsthc.so", RTLD_NOW);

         if(handle == NULL)

         {

                   fprintf(stderr, "Failed to load libsthc.so: %s/n", dlerror());

                   return 1;

         }

         dlerror();

 

         *(void **)(&fcn) = dlsym(handle, "add");     //ok

         //fcn = dlsym(handle, "add");                        //not ok in c++

         if((errmsg = dlerror()) != NULL)

         {

                   printf("%s/n", errmsg);

                   return 1;

         }

         printf("%d/n", fcn(1, 5));

        

         dlclose(handle);

         return 0;

}

 

#makefile

cppdltest:cppdltest.o

         g++ cppdltest.o -ldl -lsthc -o cppdltest

cppdltest.o:cppdltest.cpp

         g++ -c cppdltest.cpp -o cppdltest.o

all:cppdltest

clean:

         rm -f *.o cppdltest

 

 

2. 用 c++ 语言写动态库:

/*

  * libsthcpp.h

  * Declarations for function cppadd

  */

#include "stdio.h"

#include "stdlib.h"

#include "stdarg.h"

#ifdef __cplusplus

extern "C"

{

#endif

 

int cppadd(int x, int y);

#ifdef __cplusplus

}

#endif

 

 

/*

  * libsthcpp.cpp

  * Implementation of function cppadd declared in libsthcpp.h

  * in c++ language

  */

#include "libsthcpp.h"

 

int cppadd(int x, int y)

{

         return x + y;

}

 

#makefile

libsthcpp.so:libsthcpp.o

         g++ -g -shared -Wl libsthcpp.o -lc -o libsthcpp.so

libsthcpp.o:libsthcpp.cc libsthcpp.h

         g++ -g -fPIC -c libsthcpp.cc -o libsthcpp.o

all:libsthcpp.so

clean:

         rm -f *.o *.so

 

make 完成后,会生成一个动态库,即 libsthcpp.so 。为了使其他程序也可以使用该动态库,需要将库文件 libsthcpp.so 拷贝到/usr/lib 目录下 ( 由于权限的问题,一般要以 root 的身分进行拷贝 ) ,为了使其他程序也可以使用该动态库,需要将头文件libsthcpp.h 拷贝到 /usr/include 目录下 ( 由于权限的问题 , 一般要以 root 的身分进行拷贝 ) 。

 

2.1 用 c 语言静态方式调用动态库 libsthcpp.so :

/*

  * ctest.c

  * Testing program for libsthcpp.so library

  * in c languange

  * by 玄机逸士

*/

#include "libsthcpp.h"

int main(void)

{

         printf("%d/n", cppadd(1, 2));

         return 0;

}

 

#makefile

ctest:ctest.o

         gcc ctest.o -lsthcpp -o ctest

ctest.o:ctest.c

         gcc -c ctest.c -o ctest.o

all:ctest

clean:

         rm -f *.o ctest

 

 

2.2 用 c 语言动态方式调用动态库 libsthcpp.so :

/*cdltest.c*/

#include "stdio.h"

#include "stdlib.h"

#include "dlfcn.h"

 

int main(void)

{

         void *handle;

         int (*fcn)(int x, int y);

         const char *errmsg;

        

         /* open the library */

         handle = dlopen("libsthcpp.so", RTLD_NOW);

         if(handle == NULL)

         {

                   fprintf(stderr, "Failed to load libsthc.so: %s/n", dlerror());

                   return 1;

         }

         dlerror();

 

         //*(void **)(&fcn) = dlsym(handle, "cppadd");       //ok in c and c++

         fcn = dlsym(handle, "cppadd");                               //ok in c, but not in c++

         if((errmsg = dlerror()) != NULL)

         {

                   printf("%s/n", errmsg);

                   return 1;

         }

         printf("%d/n", fcn(1, 5));

        

         dlclose(handle);

         return 0;

}

 

#makefile

cdltest:cdltest.o

         gcc cdltest.o -ldl -lsthcpp -o cdltest

cdltest.o:cdltest.c

         gcc -c cdltest.c -o cdltest.o

all:cdltest

clean:

         rm -f *.o cdltest

 

2.3 用 c++ 语言静态方式调用动态库 libsthcpp.so :

/*

  * cpptest.cpp

  * Testing program for libsthc.so library written in c language

  * in c++ languange

  * by 玄机逸士

*/

#include "libsthcpp.h"

#include "iostream.h"

int main(void)

{

         cout << cppadd(1, 2) << endl;

         return 0;

}

 

#makefile

cpptest:cpptest.o

         g++ cpptest.o -lsthcpp -o cpptest

cpptest.o:cpptest.cpp

         g++ -c cpptest.cpp -Wno-deprecated -o cpptest.o

all:cpptest

clean:

         rm -f *.o cpptest

 

2.4 用 c++ 语言动态方式调用动态库 libsthcpp.so :

/*cppdltest.cpp*/

#include "stdio.h"

#include "stdlib.h"

#include "dlfcn.h"

 

int main(void)

{

         void *handle;

         int (*fcn)(int x, int y);

         const char *errmsg;

        

         /* open the library */

         handle = dlopen("libsthcpp.so", RTLD_NOW);

         if(handle == NULL)

         {

                   fprintf(stderr, "Failed to load libsthc.so: %s/n", dlerror());

                   return 1;

         }

         dlerror();

 

         *(void **)(&fcn) = dlsym(handle, "cppadd");         //ok in c and c++

         //fcn = dlsym(handle, "cppadd");                             //ok in c, but not in c++

         if((errmsg = dlerror()) != NULL)

         {

                   printf("%s/n", errmsg);

                   return 1;

         }

         printf("%d/n", fcn(1, 5));

        

         dlclose(handle);

         return 0;

}

 

#makefile

cppdltest:cppdltest.o

         g++ cppdltest.o -ldl -lsthcpp -o cppdltest

cppdltest.o:cppdltest.cpp

         g++ -c cppdltest.cpp -o cppdltest.o

all:cppdltest

clean:

         rm -f *.o cppdltest


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值