c++动态库调用外部函数汇总。
1,基本使用动态库示例
#include <stdio.h> int func_in_lib(int k) { printf("func_in_lib is called "); return k + 1; }
[clear#] gcc -fPIC --shared -o lib.so lib.c
如上的lib.so库,可直接引用动态库即可。
使用系统方法条用动态库:
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <dlfcn.h> typedef int (*pfunc)(int); void func_in_main(void) { printf("func_in_main "); } int main(int argc, char *agv[]) { int a = 1; int b; // 打开动态库 void *handle = dlopen("./lib.so", RTLD_NOW); if (handle) { // 查找动态库中的函数 pfunc func = (pfunc) dlsym(handle, "func_in_lib"); if (func) { b = func(a); printf("b = %d ", b); } else { printf("dlsym failed! "); } dlclose(handle); } else { printf("dlopen failed! "); } return 0; }
[root]# ./main func_in_lib is called b = 2
如上调用没有任何问题,一切正常。
如果需要再动态库中调用外部的函数,需要注意的几点,总结如下,如下例子:
#include <stdio.h> // 外部函数声明 void func_in_main(void); int func_in_lib(int k) { printf("func_in_lib is called "); func_in_main(); return k + 1; } 如上示例,在库中声明一个函数,并调用,外部函数实现外部。
此刻之前的main并没有做任何修改,直接运行main程序,结果如下:
[root@#] ./main
dlopen failed!
运行打开库失败了。
原因:动态库引用了外部函数,仅仅只是在库中进行了声明,但是使用者并未制定外部函数的实现,没有指定对应函数地址,动态库执行中因找不到导致报错。
解决方法:需要将外部函数的符号倒进去,并且main在自身内提供一个func_in_main方法的实现,编译时需要将该方法的符号地址倒入。如下几个案列:
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <dlfcn.h> typedef int (*pfunc)(int); void func_in_main(void) { printf("func_in_main "); } int main(int argc, char *agv[]) { int a = 1; int b; // 打开动态库 void *handle = dlopen("./lib.so", RTLD_NOW); if (handle) { // 查找动态库中的函数 pfunc func = (pfunc) dlsym(handle, "func_in_lib"); if (func) { b = func(a); printf("b = %d ", b); } else { printf("dlsym failed! "); } dlclose(handle); } else { printf("dlopen failed! "); } return 0; }
[root@dynamic]# gcc -m32 -fPIC --shared -o lib.so lib.c [root@dynamic]# gcc -g -o main main.c -ldl
[root@dynamic]# ./main dlopen failed!
如上虽然提供了外部函数的实现,编译程序时因没有将外部函数的符号地址倒入,执行时动态库仍旧找不到,所以就撂挑子不干啦。
查看导出的符号表 [root@/data/myC++/dynamic]# $ objdump -e main -T | grep func_in_main [root@/data/myC++/dynamic]# # 这里输出为空
因为如上仅仅是在可执行程序添加了外部函数,func_in_main函数符号并没倒出来。
修改如上编译:
<1>修改外部符号导出-所有符号:
[root#dynamic]gcc -m32 -rdynamic -o main main.c -ldl
[root#dynamic] ./main
func_in_lib is called func_in_main b = 2
<2>将指定符号罗列出来,
export.txt罗列需要倒出的方法符号:
{ extern "C" { func_in_main; }; };
[root@dynamic]# gcc -m32 -Wl,-dynamic-list=./exported.txt -o main main.c -ldl
[root@dynamic] ./main
func_in_lib is called func_in_main b = 2
以上两种方法,即可即决,动态库调用外部函数处理方式。
2.变更修改方式:
a.在动态库中可以将自己需要被执行的函数注册到动态库中,可以设置默认值。如下:
lib.c
#include <stdio.h> // 默认实现 void func_in_main_def(void) { printf("the main is lazy, do NOT register me! "); } // 定义外部函数指针 void (*func_in_main)() = func_in_main_def; void register_func(void (*pf)()) { func_in_main = pf; } int func_in_lib(int k) { printf("func_in_lib is called "); if (func_in_main) func_in_main(); return k + 1; }
main.c
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <dlfcn.h> typedef int (*pfunc)(int); typedef int (*pregister)(void (*)()); // 控制注册函数的宏定义 #define REG_FUNC #ifdef REG_FUNC void func_in_main(void) { printf("func_in_main "); } #endif int main(int argc, char *agv[]) { int a = 1; int b; // 打开动态库 void *handle = dlopen("./lib.so", RTLD_NOW); if (handle) { #ifdef REG_FUNC // 查找动态库中的注册函数 pregister register_func = (pregister) dlsym(handle, "register_func"); if (register_func) { register_func(func_in_main); } #endif // 查找动态库中的函数 pfunc func = (pfunc) dlsym(handle, "func_in_lib"); if (func) { b = func(a); printf("b = %d ", b); } else { printf("dlsym failed! "); } dlclose(handle); } else { printf("dlopen failed! "); } return 0; }
如上使用dlopen调用,执行如下结果:
[root@/myC++/dynamic]# gcc -m32 -o main main.c -ldl [root@/myC++/dynamic]# ./main func_in_lib is called the main is lazy, do NOT register me! b = 2
如上提示:the main is lazy, do NOT register me! ,因为没有主动注册,可以忽略,如果不想出现提示,就注册一个函数即可。
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <dlfcn.h> typedef int (*pfunc)(int); typedef int (*pregister)(void (*)()); // 控制注册函数的宏定义 #define REG_FUNC #ifdef REG_FUNC void func_in_main(void) { printf("func_in_main "); } #endif int main(int argc, char *agv[]) { int a = 1; int b; // 打开动态库 void *handle = dlopen("./lib.so", RTLD_NOW); if (handle) { #ifdef REG_FUNC // 查找动态库中的注册函数 pregister register_func = (pregister) dlsym(handle, "register_func"); if (register_func) { register_func(func_in_main); } #endif // 查找动态库中的函数 pfunc func = (pfunc) dlsym(handle, "func_in_lib"); if (func) { b = func(a); printf("b = %d ", b); } else { printf("dlsym failed! "); } dlclose(handle); } else { printf("dlopen failed! "); } return 0; }