文章目录
- windows系统
- linux系统
- windows 与 linux下 C 调用动态库的差异
C语言调用动态链接库
windows系统
windows系统下,C语言调用win下的动态库dll,使用头文件<windows.h>。
- 准备基础C代码 lauf.c
#include <stdio.h>// 定义函数,并发布到 共享库dll
int lauf(char* ptr) {printf("%s-%s\n", __FILE__, ptr);return 0;
}
- 编译共享库 lauf.dll
# 编译为共享库
gcc ./lauf.c -fPIC -shared -o lauf.dll# 查看lauf.dll中的symbol
strings lauf.dll | findstr lauf
# 使用objdump查看
objdump -p lauf.dll | findstr lauf
- 编写调用动态库的C代码 main.c
#include <stdio.h>
#include <windows.h>int main() {// 加载动态库HINSTANCE winDll;winDll = LoadLibrary(TEXT("lauf.dll"));if (winDll == NULL) {printf("加载dll失败\n");return 1;}// 获取winDll 中的符号(函数或者变量)// 不确定函数的返回类型、参数类型时,自定义函数指针typedef int (*MyFunc)(char*); // 自定义 函数指针 类型,使用该类型声明变量MyFunc func;// 定位符号func = (MyFunc)GetProcAddress(winDll, "lauf");if (func == NULL) {printf("获取符号失败\n");return 1;}// 调用函数char* name = "main-jack";int result = func(name); // 返回整型printf("函数调用结果:%d\n", result);return 0;}
- 编译 main.c 成为 main.exe
# 编译
gcc ./main.c -o main.exe -L. -l lauf
# -L 指定加载的动态链接库的 路径,如 -L . 从当前目录加载
# -l 指定使用的动态链接库名,如-l lauf,注意不带dll扩展名
# 至少指定一个L,或者两者同时指定,如 -L . -l lauf# -I 指定使用的 头文件路径# g++ 编译C++ 方式类似
调用main.exe 输出结果:
linux系统
C语言调用linux下的动态库so,使用头文件<dlfcn.h>,下面以CentOS为例说明。
- 准备C代码,并编译为so
base.c
#include <stdio.h>int funcBase(){printf("func base is running...");return 10;
}
lauf.c
#include <stdio.h>// 定义变量
char *username = "jack";
char *funcLauf(char* ptr){printf("%s-username:%s\n", __FILE__, ptr);return ptr;}
main.c
#include <stdio.h>// declare func defined in other c source.
extern int funcBase();
extern char* funcLauf(char* ptr);// declare global variable
extern char* username;// 入口函数
int main(){int result = funcBase();printf("%s-result:%d\n", __FILE__, result);char* name = funcLauf(username);printf("%s-name: %s\n", __FILE__, name);return 0;
}
编译可执行程序:
# 命令行下编译,指定需要编译的所有C源文件,其他目录下的也可以指定
gcc ./*.c -o app.out# 编译为动态共享库
gcc -fPIC ./*.c -shared -o app.so
图中的app.out 是在linux下编译的可执行程序, ./app.out 即可执行
- 编写C代码,调用上一步的so(共享库、动态库);
- 使用头文件 < d l f c n . h > <dlfcn.h> <dlfcn.h> ,仅linux环境下用
- void *dlopen(const char *filename, int flag),打开一个动态库;如dlopen(“xxx.so”, RTLD_LAZY)
- void *dlsym(void *handle, const char *symbolName),获取动态库中的函数/变量(符号);如dlsym(ptr, “func”)
- int dlclose(void *handle),关闭一个动态库;
- char *dlerror(void): 返回上一个动态链接库错误的字符串描述。
- 使用 LD_PRELOAD 环境变量
- 使用 -l 编译器选项链接库文件
- 使用头文件 < d l f c n . h > <dlfcn.h> <dlfcn.h> ,仅linux环境下用
// 这里用 <dlfcn.h> 使用动态库的头文件方式
#include <stdio.h>
#include <dlfcn.h> // 使用动态库的头文件int main() {void *handle = NULL;char* (*func)(char*); // ptr of funcchar *error = NULL;char* username = "jack";// load libhandle = dlopen("app.so", RTLD_LAZY); // lazy loadif (!handle) {fprintf(stderr, "%s\n", dlerror()); // 错误信息输入到dlerrorreturn 1;}// get func inner sofunc = dlsym(handle, "funcLauf");if ((error = dlerror()) != NULL) { // 有错误输出fprintf(stderr, "%s\n", error);return 1;}// 函数调用printf("Result: %s\n", func(username));// close so ptrdlclose(handle);return 0;
}
编译可执行文件:
# compile
gcc moduleCallSo.c -o moduleCallSo.out -ldl
# gcc, compiler
# moduleCallSo.c, C source file
# -o, output to a file
# -l, to include dynamic lib, 'dl' is dynamic linked lib
执行结果: