1、介绍 动态库是程序设计常用的技术,采用动态库可以有效的减少程序大小,节省空间,提高效率,增加程序的可扩展性,便于模块化管理。在Windows和Linux 操作系统中都有动态库的概念。Windows将其称为动态链接库(Dynamic Link Library,DLL),其文件扩展名为.dll,Linux称其为共享库技术(Shared Library),相应的共享库文件扩展名为.so。 故名思义,动态库在程序运行的时候被动态链接。但是在具体使用动态库的时候却有两种不同的方式:隐式链接和显式链接。隐式链接在编译/链接阶段完成,由编译 系统根据动态库的头文件和库文件进行编译和链接,从而确定待调用的函数原形和地址。显式链接则是利用API函数实现加载和卸载共享库,获取带调用函数地 址,获取错误信息等功能。 2、隐式链接举例 (1)动态库文件代码:dl_func.c #include <stdio.h> 该文件中的add()函数计算两个整数之和,并且打印外部变量的值,该外部变量由调用共享库的事例程序定义。 (2)客户端事例代码:dl_demo1.c #include <stdio.h> int add(int a, int b); char name[100]; strcpy(name, "NHN XDBMS"); return 0; 该事例程序调用共享库的中的add()函数计算两数之后并打印,同时在事例程序中,给变量name赋值,以便在add()函数中打印。 (3)编译与运行 编译共享库: gcc -o libdl_func.so -fPIC -rdynamic -shared dl_func.c 编译事例程序: gcc -o dl_demo1 -L./ -ldl_func dl_demo1.c 运行: ./dl_demo1 输出: calling add 3、显式链接API函数 显式链接主要涉及到4个API函数( dlopen , dlerror , dlsym 和 dlclose ),这些函数原形定义包含在dlfcn.h头文件中。 (1)void *dlopen(const char *file, int mode); 该函数用来按照指定模式打开指定的共享库,将其影射到内存中,并且返回句柄。 (2)void *dlsym(void *restrict handle, const char *restrict name); 该函数返回一个指向由name所确定的请求入口点的指针。调用dlsym时,利用dlopen()返回的共享库的phandle以及函数/变量名称作为参数,返回要加载函数/变量的入口地址。 (3)char *dlerror(void); dlerror 返回 NULL 或者一个指向描述最近错误的 ASCII 字符串的指针 (4)int dlclose(void *handle); 关闭句柄并且取消共享目标文件的映射 4、显式链接举例 (1)动态库文件代码:dl_func.c 与隐式链接的代码相同。 (2)客户端事例代码:dl_demo.c #include <stdio.h> char name[100]; strcpy(name, "NHN XDBMS"); c = add(a, b); 该事例程序给变量name赋值,以便在add()函数中打印。程序利用dlopen函数加载共享库libdl_func.so,利用dlclose关闭句柄,利用dlerror获取错误信息,利用dlsym定位共享库中的add函数,然后调用该函数执行加法计算。 (3)编译与运行 编译共享库: 与前述共享库编译方法相同。 编译事例程序: gcc -o dl_demo -fPIC -ldl dl_demo.c 运行: ./dl_demo 输出: 与隐式链接事例的输出相同。 5、其他 (1)如事例中所给出的,除了共享库可以给别人使用外,共享库也可以使用调用程序中的变量,如在共享库中打印事例程序中的name。不过由于name在外部定义和声明因此在链接共享库时需要使用-shared选项。 (2)除了可以共享函数外,还可以共享变量,如果在dl_func.c中定义个变量: int num = 100; 那么可以在事例程序中这样调用: int *d; |