使用函数指针,实现一个实用的C语言框架

2023-11-02

    在上一篇《 Qt动态库加载之 QLibrary  》 一文中,和大家分享了Qt 编译和调用C动态库的方法。在动态库中,我们使用了函数指针,借用函数指针实现C语言中的“多态”;其次,在库中我们实现固定的算法和业务,将可能会更改的部分以接口的形式抛出,用户在调用时也可以更加灵活,在一定程度上起到了解耦的作用。

#ifndef CBB_MYLOG_H
#define CBB_MYLOG_H


#if defined(CBB_LIBRARY)
#  define _API extern "C" __declspec(dllexport)
#else
#  define _API extern "C" __declspec(dllimport)
#endif

typedef void (*cbb_func)(void* ref,int len);

typedef struct cbb_data
{
    cbb_func func;  
    void* ref;
    int len;
}cbb_t,*p_cbb;

enum log_level{
    LEVEL1,
    LEVEL2,
    LEVEL3
};

_API void cbb_mylog(p_cbb pb,log_level level,char* f,...);
#endif // CBB_MYLOG_H
#include "cbb_mylog.h"
#include <stdio.h>
#include <stdarg.h>

void cbb_mylog(p_cbb pb, log_level level, char *f,...)
{
    if ( nullptr != pb ) pb->func(pb->ref,pb->len);  # 回调函数

    char buf[4000] = {0};
    va_list args;
    va_start(args, f);
    vsprintf(buf, f,args);
    va_end(args);

    printf("%s\n",buf);
}

用户在调用C动态库时,可以实现 自己的 typedef void (*cbb_func)(void* ref,int len);

#include <QCoreApplication>
#include <QLibrary>
#include <QDebug>

typedef void (*cbb_func)(void* ref,int len);

typedef struct cbb_data
{
    cbb_func func;
    void* ref;
    int len;
}cbb_t,*p_cbb;

enum log_level{
    LEVEL1,
    LEVEL2,
    LEVEL3
};

typedef void (*cb_func)(p_cbb pb,log_level level,char* f,...);
typedef int (*padd)(int x,int y);

void show_help(void* ref,int len){
    printf("%s %d show_help \n",__FILE__,__LINE__);
}

void show_help2(void* ref,int len){
    printf("%s %d show_help2 \n",__FILE__,__LINE__);
}

void show_help3(void* ref,int len){
    printf("%s %d show_help3 \n",__FILE__,__LINE__);
}

// ...

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QString library_path = QCoreApplication::applicationDirPath() + "/cbb_frame.dll";
    QLibrary* L = new QLibrary(library_path);

    if( nullptr == L) return -1;

    if(! L->load()){
        qDebug() << "[error:]" << L->errorString();
        delete L;
        L = NULL;
    }

    // 如下,均调用动态库中的cbb_mylog 方法,但由于我们传入的函数指针不同,
    // 程序在运行时,产生了不同的运行状态和结果,实现了C语言的“多态”

    // ![1]
    cb_func myprintf = (cb_func)L->resolve("cbb_mylog");

    cbb_t cbb = {show_help,NULL,0};
    myprintf(&cbb,LEVEL1,"%s","show_help");

    // ![2]
    cbb_t cbb2 = {show_help2,NULL,0};
    myprintf(&cbb2,LEVEL1,"%s","show_help2");

    // ![3]
    cbb_t cbb3 = {show_help3,NULL,0};
    myprintf(&cbb3,LEVEL1,"%s","show_help3");

    L->unload();

    return a.exec();
}

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用函数指针,实现一个实用的C语言框架 的相关文章

  • 使用 gcc 在 Linux 上运行线程构建块 (Intel TBB)

    我正在尝试为线程构建块构建一些测试 不幸的是 我无法配置 tbb 库 链接器找不到库 tbb 我尝试在 bin 目录中运行脚本 但这没有帮助 我什至尝试将库文件移动到 usr local lib 但这又失败了 任何的意见都将会有帮助 确定您
  • C# 异步等待澄清?

    我读了here http blog stephencleary com 2012 02 async and await html that 等待检查等待的看看它是否有already完全的 如果 可等待已经完成 那么该方法将继续 运行 同步
  • 没有特殊字符的密码验证器

    我是 RegEx 的新手 已经进行了大量搜索 但没有找到任何具体内容 我正在编写一个验证密码字符串的正则表达式 可接受的字符串必须至少具有 4 种字符类型中的 3 种 数字 小写字母 大写字母 特殊字符 我对包含有一个想法 也就是说 如果这
  • 通过引用传递 [C++]、[Qt]

    我写了这样的东西 class Storage public Storage QString key const int value const void add item QString int private QMap
  • 如何在 Cassandra 中存储无符号整数?

    我通过 Datastax 驱动程序在 Cassandra 中存储一些数据 并且需要存储无符号 16 位和 32 位整数 对于无符号 16 位整数 我可以轻松地将它们存储为有符号 32 位整数 并根据需要进行转换 然而 对于无符号 64 位整
  • 如何在 C++ 中标记字符串?

    Java有一个方便的分割方法 String str The quick brown fox String results str split 在 C 中是否有一种简单的方法可以做到这一点 The 增强分词器 http www boost o
  • 用于 FTP 的文件系统观察器

    我怎样才能实现FileSystemWatcherFTP 位置 在 C 中 这个想法是 每当 FTP 位置添加任何内容时 我都希望将其复制到我的本地计算机 任何想法都会有所帮助 这是我之前问题的后续使用 NET 进行选择性 FTP 下载 ht
  • 对类 static constexpr 结构的未定义引用,g++ 与 clang

    这是我的代码 a cp p struct int2 int x y struct Foo static constexpr int bar1 1 static constexpr int2 bar2 1 2 int foo1 return
  • C++ 多行字符串原始文字[重复]

    这个问题在这里已经有答案了 我们可以像这样定义一个多行字符串 const char text1 part 1 part 2 part 3 part 4 const char text2 part 1 part 2 part 3 part 4
  • 重载 (c)begin/(c)end

    我试图超载 c begin c end类的函数 以便能够调用 C 11 基于范围的 for 循环 它在大多数情况下都有效 但我无法理解和解决其中一个问题 for auto const point fProjectData gt getPoi
  • ASP.NET Core 3.1登录后如何获取用户信息

    我试图在登录 ASP NET Core 3 1 后获取用户信息 如姓名 电子邮件 id 等信息 这是我在登录操作中的代码 var claims new List
  • C# - 当代表执行异步任务时,我仍然需要 System.Threading 吗?

    由于我可以使用委托执行异步操作 我怀疑在我的应用程序中使用 System Threading 的机会很小 是否存在我无法避免 System Threading 的基本情况 只是我正处于学习阶段 例子 class Program public
  • 实例化类时重写虚拟方法

    我有一个带有一些虚函数的类 让我们假设这是其中之一 public class AClassWhatever protected virtual string DoAThingToAString string inputString retu
  • C 函数 time() 如何处理秒的小数部分?

    The time 函数将返回自 1970 年以来的秒数 我想知道它如何对返回的秒数进行舍入 例如 对于100 4s 它会返回100还是101 有明确的定义吗 ISO C标准没有说太多 它只说time 回报 该实现对当前日历时间的最佳近似 结
  • 在 WPF 中使用 ReactiveUI 提供长时间运行命令反馈的正确方法

    我有一个 C WPF NET 4 5 应用程序 用户将用它来打开某些文件 然后 应用程序将经历很多动作 读取文件 通过许多插件和解析器传递它 这些文件可能相当大 gt 100MB 因此这可能需要一段时间 我想让用户了解 UI 中发生的情况
  • C# 中的 IPC 机制 - 用法和最佳实践

    不久前我在 Win32 代码中使用了 IPC 临界区 事件和信号量 NET环境下场景如何 是否有任何教程解释所有可用选项以及何时使用以及为什么 微软最近在IPC方面的东西是Windows 通信基础 http en wikipedia org
  • 为什么 std::uint32_t 与 uint32_t 不同?

    我对 C 有点陌生 我有一个编码作业 很多文件已经完成 但我注意到 VS2012 似乎有以下语句的问题 typedef std uint32 t identifier 不过 似乎将其更改为 typedef uint32 t identifi
  • DotNetZip:如何提取文件,但忽略zip文件中的路径?

    尝试将文件提取到给定文件夹 忽略 zip 文件中的路径 但似乎没有办法 考虑到其中实现的所有其他好东西 这似乎是一个相当基本的要求 我缺少什么 代码是 using Ionic Zip ZipFile zf Ionic Zip ZipFile
  • 如何确定 CultureInfo 实例是否支持拉丁字符

    是否可以确定是否CultureInfo http msdn microsoft com en us library system globalization cultureinfo aspx我正在使用的实例是否基于拉丁字符集 我相信你可以使
  • 使用 WGL 创建现代 OpenGL 上下文?

    我正在尝试使用 Windows 函数创建 OpenGL 上下文 现代版本 基本上代码就是 创建窗口类 注册班级 创建一个窗口 choose PIXELFORMATDESCRIPTOR并设置它 创建旧版 OpenGL 上下文 使上下文成为当前

随机推荐

  • 从任一结点出发到根的路径上所经过的结点序列按其关键字有序

    题目 下述二叉树中 哪一种满足性质 从任一结点出发到根的路径上所经过的结点序列按其关键字有序 a 二叉排序树 b 哈夫曼树 c avl树 d 堆 答案 d 解析 首先a 二叉排序树 B树即为二叉搜索树或称二叉排序树 Binary Sort
  • python求两个整数的最大公约数_求两个数最大公约数的三种方法(Python实现),两数,python...

    求两个数的最大公约数 有三种方法 分别是 短除法 辗转相除法 更相减损法 短除法 运用短除法找到两个数的最大公约数 具体过程是逐步找出两个数的所有公约数 再把这些公约数累乘起来 就得到两个数的最大公约数 def func1 a int in
  • CEEMDAN代码,自适应噪声完备集合经验模态分别,C++代码下载

    CEEMDAN Complete Ensemble Empirical Mode Decomposition with Adaptive Noise 的中文名称是自适应噪声完备集合经验模态分解 要注意这个方法并不是在CEEMD方法上改进而来
  • npm install 报错

    困扰很久的问题终于解决 由于要在前端导出excel文件 需要xlsx模块 于是就使用npm来导入 npm install save xlsx file saver 但是尝试了很多次均报错 信息如下 由于报错信息很长 所以只能尝试截取不同的报
  • 功能测试基础之操作测试

    功能测试基础之操作测试 文章目录 功能测试基础之操作测试 操作测试简述 操作测试的验证标准 操作测试简述 操作测试主要是检验系统中的操作对象 菜单 按钮和输入框等 的设计是否符合软件设计标准和用户的操作习惯 页面内的各对象焦点是否顺序一致
  • vue 监听返回按钮

    移动端当用户使用默认返回按钮的时候 或左滑 或点击返回键 这时候需要监听返回按钮 1 挂载完成后 判断是否支持popstate mounted if window history window history pushState histo
  • 给出两个有序的整数数组A和B,请将数组B合并到数组A中,变成一个有序的数组。

    题目 一 给出两个有序的整数数组A和B 请将数组B合并到数组A中 变成一个有序的数组 注意 可以假设A数组有足够的空间存放B数组的元素 A和B中初始的元素数目分别为m和n public void merge int A int m int
  • Ubuntu 创建本地 Git 并与 Github(私有库) 交互(上传与下载)

    1 创建本地git并上传至github 首先先附上基础的教程 写的挺靠谱的 有一点值得注意 如果还不想公开自己的代码 记得在github上创建新库的时候点那个私有的选项 https www cnblogs com sawyer22 p 92
  • eclipes快捷键使用说明

    Ctrl 1 快速修复 最经典的快捷键 就不用多说了 Ctrl D 删除当前行 Ctrl Alt 复制当前行到下一行 复制增加 Ctrl Alt 复制当前行到上一行 复制增加 Alt 当前行和下面一行交互位置 特别实用 可以省去先剪切 再粘
  • Error during artifact deployment. See server log for details.

    实体类的double改成Double竟然启动报错这个 你敢信 感觉是这get的问题 还以为是打包出问题了 浪费好多时间 服 public Integer getOrderY return int y 5 public void setOrd
  • C#web启用目录查询功能

    当出现如下情况 直接找到iis安装目录 C Program Files IIS Express 然后cmd打开黑窗口 进入iis安装目录 cd C Program Files IIS Express 然后执行命令 把如图提示的命令 appc
  • 11个点告诉你 如何用Docker+jenkins 运行 python 自动化

    一 实现思路 在 Linux 服务器安装 docker 创建 jenkins 容器 根据自动化项目依赖包构建 python 镜像 构建自动化 python 环境 运行新的 python 容器 执行 jenkins 从仓库中拉下来的自动化项目
  • 浩辰CAD2021中文版

    教程 1 下载解压压缩包文件 得到64 32位安装包及文件 根据系统选择合适的安装包运行 进入安装引导界面 资源地址在评论区 2 进入安装引导后 选择软件的安装目录 正常默认即可 有需要的话也可自行更改 别忘记勾选同意软件许可协议 3 点击
  • 资深java软件工程师给大家的忠告

    java学习这一部分其实也算是今天的重点 这一部分用来回答很多群里的朋友所问过的问题 那就是我你是如何学习Java的 能不能给点建议 今天我是打算来点干货 因此咱们就不说一些学习方法和技巧了 直接来谈每个阶段要学习的内容甚至是一些书籍 这一
  • tomcat 虚拟节点

  • ContextLoaderListener作用详解

    ContextLoaderListener作用详解 1 目的 了解ContextLoaderListener的作用 2 作用 2 1 ContextLoaderListener监听器 1 ContextLoaderListener监听器的作
  • python利用opencv进识别行红绿灯

    目录 一 使用步骤 1 引入库 2 读入数据 3 获取帧率 4 创建函数将鼠标在图片中点击的坐标储存 5 逐帧采集视频并显示一帧图片来选择roi区域 6 最后逐帧采集视频并且放入循环一帧一帧的判断感兴趣区域中亮起的灯是哪个 二 全部代码 总
  • ChatGPT入门教程大纲

    第一部分 ChatGPT基础知识 ChatGPT概述 什么是ChatGPT ChatGPT的应用领域 ChatGPT的工作原理 语言模型和深度学习的概念 Transformer架构的介绍 预训练和微调的过程 ChatGPT的应用案例 与Ch
  • Linux·libusb源码编译

    libusb系列 Linux下libusb源码编译 源码下载及解压 下载源码 解压下载的源码压缩包 打开终端 准备编译环境 安装make dh autoreconf 安装 libudev dev sudo autogen sh sudo c
  • 使用函数指针,实现一个实用的C语言框架

    在上一篇 Qt动态库加载之 QLibrary 一文中 和大家分享了Qt 编译和调用C动态库的方法 在动态库中 我们使用了函数指针 借用函数指针实现C语言中的 多态 其次 在库中我们实现固定的算法和业务 将可能会更改的部分以接口的形式抛出 用