lib静态库最常见的场景是外部函数来调用lib库中的函数,但是存在有些场景,需要lib库和外部函数做一个交互,这种场景往往存在于内存资源和计算资源有限的单片机中,部署在单片机上的算法库尝尝需要调用主机上的函数。因为资源限制问题,单片机无法加载动态so库,所以需要实现静态lib主动调用主机代码的一些函数,这种情况下,应该怎么处理呢?
使用注册函数就可以实现这个功能,注册函数是以函数指针参数的形式去调用各个函数,这涉及到回调函数和注册函数的关系。注册函数就像一个酒杯,而回调函数像各种酒品,比如白酒,红酒,果酒,注册函数可以自己选择装哪种酒品,二者的关系可以从下述代码中看出:
#include
/* 函数指针 */
typedef int (*ptrFunc)(int, int);
/* 声明 */
int Register(ptrFunc callBack, int a, int b);
/* 回调函数 */
int fun1(int a, int b){
return a + b;
}
int fun2(int a, int b){
return a - b;
}
/* 注册函数 */
int Register(ptrFunc callBack, int a, int b) {
int res = callBack(a, b);
printf("res = %d\n", res);
return 1;
}
/* main */
void main(){
int a = 3;
int b = 1;
/* 回调函数fun1 */
Register(fun1, a, b);
/* 回调函数fun2 */
Register(fun2, a, b);
}
如上述代码,注册函数可以随意调用回调函数,但是要确保回调函数的参数类型和注册函数的参数类型是一样的。
那回调函数和注册函数怎么解决我们的问题呢?我们只需要在lib库中注册一个我们想要调用的函数类型即可,函数的实现在主机上,这样lib库就可以调用我们主机中的函数了。比如我们想在lib库中调用我们的主机中fun1()的函数,我们的lib库的头文件和C文件可以这么写:
头文件, libTest.c
#ifndef _LIBTEST_H
#define _LIBTEST_H
/*
注意,函数指针和声明应该放在头文件中,方便加载lib库的时候可以找到注册函数
*/
/* 函数指针 */
typedef int (*ptrFunc)(int, int);
/* 声明 */
int Register(ptrFunc callBack, int a, int b);
#endif
C文件,libTest.c
#include
#include "libTest.h" // 注意引入头文件
/* 注册函数 */
int Register(ptrFunc callBack, int a, int b) {
int res = callBack(a, b);
printf("res = %d\n", res);
return 1;
}
然后直接生成lib库即可,具体生成lib库的方法可以参考《Visual Studio 2019:创建静态库》
生成lib库之后,我们需要在C工程实现fun1函数并把lib库加载进来即可,常用的两种加载lib库的方式有两种,
#include "..\libTest\libTest.h" // 此处需要包含lib库的头文件,..\是上层目录, .\是本层目录
#pragma comment(lib, "libTest.lib") // 利用pragma comment调用lib库
/* 实现lib库要调用的主机函数 */
int fun1(int a, int b) {
return a + b;
}
void main() {
/* 在主函数中直接引用注册函数 */
Register(fun1, 1, 8);
}
这种方法在Visual Studio中还需要添加附加库路径,具体方法为:
右击工程名–>属性–>链接器–>常规–>附加库目录
在附加库目录中添加你lib库的绝对路径即可。
运行结果为:
#include "..\libTest\libTest.h" // 此处需要包含lib库的头文件,..\是上层目录, .\是本层目录
/* 实现lib库要调用的主机函数 */
int fun1(int a, int b) {
return a + b;
}
void main() {
/* 在主函数中直接引用注册函数 */
Register(fun1, 1, 8);
}
运行结果为:
通过lib库调用外部函数,总结下来一句话,lib注册一个和要调用函数参数类型一致的函数,然后再本机函数中,进行实现即可。
1. C语言 - 注册函数、回调函数(callback)以及多态的实现
2. Visual Studio 2019:创建静态库
3. C静态库(lib)及动态库(dll)的创建及调用
4. C/C++ 静态链接库(lib)的三种常用调用方式