• Tips--lib静态库调用外部函数


    前言

    lib静态库最常见的场景是外部函数来调用lib库中的函数,但是存在有些场景,需要lib库和外部函数做一个交互,这种场景往往存在于内存资源和计算资源有限的单片机中,部署在单片机上的算法库尝尝需要调用主机上的函数。因为资源限制问题,单片机无法加载动态so库,所以需要实现静态lib主动调用主机代码的一些函数,这种情况下,应该怎么处理呢?

    1. 注册函数与回调函数

    使用注册函数就可以实现这个功能,注册函数是以函数指针参数的形式去调用各个函数,这涉及到回调函数和注册函数的关系。注册函数就像一个酒杯,而回调函数像各种酒品,比如白酒,红酒,果酒,注册函数可以自己选择装哪种酒品,二者的关系可以从下述代码中看出:

    #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);
    }
    

    如上述代码,注册函数可以随意调用回调函数,但是要确保回调函数的参数类型和注册函数的参数类型是一样的

    2. lib库的生成

    那回调函数和注册函数怎么解决我们的问题呢?我们只需要在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:创建静态库

    3. lib库调用外部函数

    生成lib库之后,我们需要在C工程实现fun1函数并把lib库加载进来即可,常用的两种加载lib库的方式有两种,

    • 第一种是利用#pragma comment的方法,具体的代码实现如下:
      readLib.c文件:
    #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库的绝对路径即可
    运行结果为:
    在这里插入图片描述

    • 第二种是直接把lib库添加到工程中,如下图所示:
      在这里插入图片描述
      具体的代码实现如下:
      readLib.c文件:
    #include "..\libTest\libTest.h"  // 此处需要包含lib库的头文件,..\是上层目录, .\是本层目录
    
    /* 实现lib库要调用的主机函数 */
    int fun1(int a, int b) {
    	return a + b;
    }
    
    void main() {
    	/* 在主函数中直接引用注册函数 */
    	Register(fun1, 1, 8);
    }
    

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

    4. 总结

    通过lib库调用外部函数,总结下来一句话,lib注册一个和要调用函数参数类型一致的函数,然后再本机函数中,进行实现即可。

    参考链接

    1. C语言 - 注册函数、回调函数(callback)以及多态的实现
    2. Visual Studio 2019:创建静态库
    3. C静态库(lib)及动态库(dll)的创建及调用
    4. C/C++ 静态链接库(lib)的三种常用调用方式

  • 相关阅读:
    【JavaScript】快速学习JS
    [附源码]Java计算机毕业设计SSM防疫卫生资讯推荐系统
    信息解码(Message Decoding, ACM/ICPC World Finals 1991, UVa 213)rust解法
    HCIP第十一天笔记
    vue3学习(十五)--- Pinia状态管理器
    【毕业设计】模块介绍:人体红外热释电传感器 -物联网 嵌入式 单片机
    代码随想录-025-383.赎金信
    从Spring为什么要用IoC的支点,我撬动了整个Spring的源码脉络!
    软件工程评级B-,有大量调剂名额。北京联合大学考情分析
    【JUC源码专题】ReentrantReadWriteLock 核心源码分析(JDK8)
  • 原文地址:https://blog.csdn.net/qq_42580947/article/details/127094555