动态库和静态库在C/C++开发中很常见,相比静态库直接被编译到可执行程序,动态库运行时加载使得可执行程序的体积更小,更新动态库可以不用重新编译可执行程序等诸多好处。作者是一个Linux后台开发,这些知识经常用到,所以整理了一下这方面的知识。静态库相对简单,本文只关心Linux平台下的动态库。
创建动态库
这里我把一个短小却很有用的哈希函数编译成动态库做为示例,ELFhash用于对字符串做哈希,返回一个无符号整数。
//elfhash.h #include unsigned long ELFhash(const char* key); //elfhash.c #include "elfhash.h" unsigned long ELFhash(const char* key) { unsigned long h = 0, g; while( *key ) { h = ( h > 24; h &= ~g; } return h; } |
接下来使用gcc编译以上代码,并用ld将编译的目标文件链接成动态库
gcc -fPIC -c -Wall elfhash.c
ld -shared elfhash.o -o libelfhash.so
其中-fPIC意思是生成位置无关的代码(Position Independent Code),适用于动态库,在多个进程中共享动态库的同一份代码。ld的-shared选项告诉链接器创建的是动态库。gcc也可以间接调用ld生成动态库
gcc -fPIC -shared -Wall -o libelfhash.so elfhash.c
使用动态库
动态库的使用方法有两种一种是隐式使用,第二种是显式使用。隐式使用的方法很简单。
#include "elfhash.h"
int main()
{
printf("%ldn", ElfHash("key-for-test"));
return 0;
}
显式使用动态库需要借助以下几个函数
#include void *dlopen(const char *filename, int flag); //flag可以是RTLD_LAZY,执行共享库中的代码时解决未定义符号,RTLD_NOW则是dlopen返回前解决未定义符号。 char *dlerror(void); //当发生错误时,返回错误信息 void *dlsym(void *handle, const char *symbol); //获取符号 int dlclose(void *handle); //关闭 |
应用上面几个函数,调用ELFhash实现跟隐式调用一样的功能
#include "elfhash.h" #include #include int main() { void *handle; unsigned long (*hash)(const char*); char *error; handle = dlopen ("./libelfhash.so", RTLD_LAZY); if (!handle) { fputs (dlerror(), stderr); exit(1); } hash = dlsym(handle, "ElfHash"); if ((error = dlerror()) != NULL) { fputs(error, stderr); exit(1); } printf ("%ldn", (*hash)("key-for-test")); dlclose(handle); } |
至此了解以上的知识就可以创建和使用动态库了。 实际应用中我们可能还是会遇到一些问题。