文章目录
- 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 func
char *error = NULL;
char* username = "jack";
// load lib
handle = dlopen("app.so", RTLD_LAZY); // lazy load
if (!handle) {
fprintf(stderr, "%s\n", dlerror()); // 错误信息输入到dlerror
return 1;
}
// get func inner so
func = dlsym(handle, "funcLauf");
if ((error = dlerror()) != NULL) { // 有错误输出
fprintf(stderr, "%s\n", error);
return 1;
}
// 函数调用
printf("Result: %s\n", func(username));
// close so ptr
dlclose(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
执行结果: