C语言调用so/dll动态库


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 编译器选项链接库文件
// 这里用 <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

执行结果:
在这里插入图片描述

 

windows 与 linux下 C 调用动态库的差异

在这里插入图片描述

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

laufing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值