当前位置: 首页 > news >正文

Linux C编程:打造一个插件系统


title: ‘Linux C编程:打造一个插件系统’
date: 2017-03-07 21:16:36
tags: linux C
layout: post
comments: true

运行环境:linux
使用语言:c 或者c++

插件,很多人用过,比如游戏插件,编辑器插件这些,
最著名的就数魔兽大脚插件啦,还有vim插件啦,eclipse插件啦,等等
插件有很多种形式,最常见的就是so文件,在windows上就是各种的dll啦

下面就让我们来了解一下插件式编程吧〜〜

举个例子,你开发了一个游戏,一开始只有三个关卡,分享给了你的小伙伴玩
大家玩得很爽,但很快,游戏通关了,还想玩,这时候怎么办呢?
常规做法就是再加两关,然后编译之后,再发给大家,那么问题就来了
每次想加新关卡,都需要重新编译一次,再下载一次,这个流量嘛,1+1.1+1.2+1.3,每次加个0.1,都够你受的_
这个时候嘛,就要引入插件系统了

咱先来写个小程序

//main.c
#include <stdio.h>
#include "game.h" //关于游戏的定义void initGame()
{}
void play()
{printf("我打,我打,我打打打\n");
}
void loadMission()
{}
int main()
{initGame();//初始化游戏	int missionNum=loadMission();//读取关卡数while(1){int missionNo=getchar();//选择关卡missionNo=missionNo-'0';if(missionNo>missionNum){printf("没有此关卡!\n");}play();}}

以上就是一个可扩展的游戏架构,够简单吧〜

下面咱就开始设计这个游戏系统的插件吧

在这里,游戏关卡就是我们的插件,一个插件就是一个关卡
先讲讲一个插件的构造吧
首先是这个关卡的描述,比如名称,难度等
其次就是这个关卡游戏过程了
最后,就是玩关卡的人

按照以上描述,咱定几个结构体吧

//game.h
#include <stdio.h>
#include <string.h>
//游戏玩家描述
typedef struct _player
{int life;//玩家生命
}Player;
//游戏关卡描述
typedef struct _mission
{int level;//关卡难度char missionName[30];//关卡名称void (*process)(Player *);//游戏过程
}Mission;好了,下面就是一个插件的具体内容
```c
//game.c
#include "game.h"
const char name[]="第一关,插件入门";
const int level=1;void firstMission(Player *p)
{printf("oh my god ,somebody hurt me!\n");p->life--;printf("now my life is %d\n",p->life);sleep(1);
}
void gameInfo(Mission *m)
{m->level=level;int len=strlen(name);memcpy(m->missionName,name,len+1);//注意游戏名称不要太长m->process=firstMission;
}

Ok,以上就是一个关卡的所有东西了,虽然看着简单,不过还是建议动手敲敲_

那我们先把这个插件制作出来吧,免得一会忘记了,在终端下执行以下命令:

gcc  game.c -fPIC -shared -o firstMission.so -ldl

linux和mac都一样

关卡设计好了,接下来就是怎么样读取我们做好的关卡了

现在实现咱们就loadMission()函数

Mission mission[50];
int loadMission()
{FILE * fp;fp = fopen("missionList.txt", "r");//读取关卡列表文件if (NULL== fp)    {return 0;}int ret=0;char namelist[50][50];//最多50个插件,每个插件的名字长度最多50memset(namelist,0,sizeof(namelist));int count=0;while(fgets((char *)&namelist[count], 50, fp)) {ret=strlen(namelist[count]);//计算实际字符串长度if(namelist[count][ret-1]=='\n')namelist[count][ret-1]='\0';//fgets会读多一个换行,所以需要替换掉count++;}	 fclose(fp);ret=0;//用于累加错误次数for(int i=0;i<count;i++){const char *errmsg;dlerror();  // 清除错误void *m_hLib = (void *)dlopen(namelist[i], RTLD_LAZY);//读取插件if( (errmsg = dlerror()) != NULL ){//printf("err=%s\n",errmsg);打印错误ret++;//累加错误次数continue;}if( m_hLib == NULL ){ret++;//累加错误次数continue;}dlerror();  // 清除错误Info info = (Info)dlsym( m_hLib, "gameInfo" );//提取出插件里面的函数if( (errmsg = dlerror()) != NULL ){dlclose(m_hLib);printf("err=%s\n",errmsg);ret++;continue;}info(&mission[i]);//获取到关卡数据}ret=0;//关卡号//展示下关卡for(int i=0;i<count;i++){if(mission[i].level!=0){printf("%d.%s\n",ret+1,mission[i].missionName);/正式发布的时候就不要啦〜〜ret++;}}count=count-ret;//计算有效关卡数return count;}

好了,上面的代码,不难吧?咱编译一下,就可以跑了
linux下

gcc -o game main.c -Wl,rpath=. 

mac下

gcc -o game main.c -Wl,rpath . -dynamic

再准备一个游戏菜单文件,执行

echo firstMission.so >missionlist.txt

好了,再执行

./game 

一切顺利的话,你应该能看到自己的关卡列表了〜
接下来干嘛呢?我们现在仅仅是提取出了关卡的名字,还没开始玩游戏呢
以下是改动后的main.c文件

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include "game.h" //关于游戏的定义Mission mission[50];
void initGame()
{memset(mission,0,sizeof(mission));
}int loadMission()
{FILE * fp;fp = fopen("missionList.txt", "r");//读取关卡列表文件if (NULL== fp)    {return 0;}int ret=0;char namelist[50][50];//最多50个插件,每个插件的名字长度最多50memset(namelist,0,sizeof(namelist));int count=0;while(fgets((char *)&namelist[count], 50, fp)) {ret=strlen(namelist[count]);//计算实际字符串长度if(namelist[count][ret-1]=='\n')namelist[count][ret-1]='\0';//fgets会读多一个换行,所以需要替换掉count++;}    fclose(fp);ret=0;for(int i=0;i<count;i++){const char *errmsg;dlerror();  // 清除错误void *m_hLib = (void *)dlopen(namelist[i], RTLD_LAZY);if( (errmsg = dlerror()) != NULL ){//printf("err=%s\n",errmsg);打印错误ret++;//累加错误次数continue;}if( m_hLib == NULL ){ret++;//累加错误次数continue;}dlerror();  // 清除错误Info info = (Info)dlsym( m_hLib, "gameInfo" );if( (errmsg = dlerror()) != NULL ){dlclose(m_hLib);printf("err=%s\n",errmsg);ret++;continue;}info(&mission[i]);}//展示下关卡for(int i=0;i<count;i++){if(mission[i].level!=0){printf("%d.%s\n",i+1,mission[i].missionName);//正式发布的时候就不要啦〜〜}}count=count-ret;//计算有效关卡数return count;}
int main()
{initGame();//初始化游戏  int missionNum=loadMission();//读取关卡数if(missionNum==0){printf("游戏异常退出\n");return -1;}//初始化一个角色,并满血Player p;while(1){p.life=100;printf("请选择关卡\n");for(int i=0;i<missionNum;i++){printf("%d.%s\n",i+1,mission[i].missionName);}int missionNo=getchar();//选择关卡missionNo=missionNo-'0';if(missionNo>missionNum || missionNo<1){printf("没有此关卡!\n");continue;}//读取来的关卡肯定是有难度等级的,没有就是无效关卡if(mission[missionNo-1].level!=0){while(p.life>0)mission[missionNo-1].process(&p);}printf("Game Over!\n\n\n");}}

这就是一个完整的游戏啦,感兴趣的同学可以继续扩展哟〜〜后面就是不断得出扩展啦

你问我怎么扩展?
好吧,自己把game.c里面的内容改改,然后编译出来,换个名字,然后在missionlist.txt里面加一行,就ok了

还不懂?那你只能给我打赏了_

相关文章:

Linux C编程:打造一个插件系统

title: ‘Linux C编程:打造一个插件系统’ date: 2017-03-07 21:16:36 tags: linux C layout: post comments: true 运行环境&#xff1a;linux 使用语言&#xff1a;c 或者c 插件&#xff0c;很多人用过&#xff0c;比如游戏插件&#xff0c;编辑器插件这些&#xff0c; 最著…...

基于毫米波生物感知雷达+STM32设计的独居老人居家监护系统(微信小程序)(192)

基于毫米波生物感知雷达设计的独居老人居家监护系统(微信小程序)(192) 文章目录 一、前言1.1 项目介绍【1】项目功能介绍【2】项目硬件模块组成1.2 设计思路【1】整体设计思路【2】60G毫米波生物感知雷达原理【3】ESP8266模块配置【4】供电方式1.3 项目开发背景【1】选题的意义…...

C++——类和对象(下)

目录 一、再探构造函数 1.基本定义以及用法 2.必须在初始化列表初始化的成员变量 3.成员变量声明位置的缺省值&#xff08;C11&#xff09; 4.成员变量初始化顺序 二、隐式类型转换 三、static成员 四、友元 五、内部类 六、匿名对象 七、日期类实现 一、再探构造函数…...

Android中集成前端页面探索(Capacitor 或 Cordova 插件)待完善......

探索目标&#xff1a;Android中集成前端页面 之前使用的webview加载html页面&#xff0c;使用bridge的方式进行原生安卓和html页面的通信的方式&#xff0c;探索capacitor-android插件是如何操作的 capacitor-android用途 Capacitor 是一个用于构建现代跨平台应用程序的开源框…...

玩转CSS:用ul li +JS 模拟select,避坑浏览器不兼容。

玩转CSS&#xff1a;用ul li JS 模拟select&#xff0c;避坑浏览器不兼容。 在前端的工作中&#xff0c;经常会遇到 selcet控件&#xff0c;但我们用css来写它的样式时候&#xff0c;总是不那么令人满意&#xff0c;各种浏览器不兼容啊有没有&#xff1f; 那么&#xff0c;我…...

介绍下PolarDB

业务中用的是阿里云自研的PolarDB&#xff0c;分析下PolarDB的架构。 认识PolarDB 介绍 PolarDB是阿里云自研的&#xff0c;兼容MySQL、PostageSQL以及支持MPP的PolarDB-X的高可用、高扩展性的数据库。 架构 部署 云起实验室 - 阿里云开发者社区 - 阿里云 (aliyun.com) 数…...

基于微信小程序+SpringBoot+Vue的儿童预防接种预约系统(带1w+文档)

基于微信小程序SpringBootVue的儿童预防接种预约系统(带1w文档) 基于微信小程序SpringBootVue的儿童预防接种预约系统(带1w文档) 开发合适的儿童预防接种预约微信小程序&#xff0c;可以方便管理人员对儿童预防接种预约微信小程序的管理&#xff0c;提高信息管理工作效率及查询…...

go语言day15 goroutine

Golang-100-Days/Day16-20(Go语言基础进阶)/day17_Go语言并发Goroutine.md at master rubyhan1314/Golang-100-Days GitHub 第2讲-调度器的由来和分析_哔哩哔哩_bilibili 一个进程最多可以创建多少个线程&#xff1f;-CSDN博客 引入协程 go语言中内置了协程goroutine&#…...

Mindspore框架循环神经网络RNN模型实现情感分类|(六)模型加载和推理(情感分类模型资源下载)

Mindspore框架循环神经网络RNN模型实现情感分类 Mindspore框架循环神经网络RNN模型实现情感分类|&#xff08;一&#xff09;IMDB影评数据集准备 Mindspore框架循环神经网络RNN模型实现情感分类|&#xff08;二&#xff09;预训练词向量 Mindspore框架循环神经网络RNN模型实现…...

System类

System类常见方法 ① exit 退出当前程序 public static void main(String[] args) {System.out.println("ok1");//0表示状态&#xff0c;即正常退出System.exit(0);System.out.println("ok2");} ② arraycopy 复制数组元素 复制的数组元素个数必须<原数…...

【前端 02】新浪新闻项目-初步使用CSS来排版

在今天的博文中&#xff0c;我们将围绕“新浪新闻”项目&#xff0c;深入探讨HTML和CSS在网页制作中的基础应用。通过具体实例&#xff0c;我们将学习如何设置图片、标题、超链接以及文本排版&#xff0c;同时了解CSS的引入方式和选择器优先级&#xff0c;以及视频和音频标签的…...

HarmonyOS和OpenHarmony区别联系

前言 相信我们在刚开始接触鸿蒙开发的时候经常看到HarmonyOS和OpenHarmony频繁的出现在文章和文档之中&#xff0c;那么这两个名词分别是什么意思&#xff0c;他们之间又有什么联系呢&#xff1f;本文将通过现有的文章和网站内容并与Google的AOSP和Android做对比&#xff0c;带…...

llama模型,nano

目录 llama模型 Llama模型性能评测 nano模型是什么 Gemini Nano模型 参数量 MMLU、GPQA、HumanEval 1. MMLU(Massive Multi-task Language Understanding) 2. GPQA(Grade School Physics Question Answering) 3. HumanEval llama模型 Large Language Model AI Ll…...

ElasticSearch的应用场景和优势

ElasticSearch是一个开源的分布式搜索和分析引擎&#xff0c;它以其高性能、可扩展性和实时性在多个领域得到了广泛应用。以下是ElasticSearch的主要应用场景和优势&#xff1a; 应用场景 实时搜索&#xff1a; ElasticSearch以其快速、可扩展和实时的特性&#xff0c;成为实…...

git 、shell脚本

git 文件版本控制 安装git yum -y install git 创建仓库 将文件提交到暂存 git add . #将暂存区域的文件提交仓库 git commit -m "说明" #推送到远程仓库 git push #获取远程仓库的更新 git pull #克隆远程仓库 git clone #分支&#xff0c;提高代码的灵活性 #检查分…...

阿里云服务器 篇六:GitHub镜像网站

文章目录 系列文章搭建镜像网站的2种方式使用 Web 抓取工具 (Spider 技术)使用 Web 代理服务器使用 nginx 搭建GitHub镜像网站基础环境搭建添加对 github.com 的转发配置添加对 raw.githubusercontent.com 的转发配置配置更改注意事项(可选)缓存优化为新增设的二级域名配置DN…...

强化学习学习(三)收敛性证明与DDPG

文章目录 证明收敛&#xff1f; Deep RL with Q-FunctionsDouble Q-Learning理论上的解法实际上的解法 DDPG: Q-Learning with continuous actionsAdvanced tips for Q-Learning 证明收敛&#xff1f; 对于Value迭代&#xff1a;不动点证明的思路 首先定义一个算子 B : B V ma…...

培养前端工程化思维,不要让一行代码毁了整个程序

看《阿丽亚娜 5 号&#xff08;Ariane 5&#xff09;火箭爆炸》有感。 1、动手写项目之前&#xff0c;先进行全局性代码逻辑思考&#xff0c;将该做的事情&#xff0c;一些细节&#xff0c;统一建立标准&#xff0c;避免为以后埋雷。 2、避免使用不必要或无意义的代码、注释。…...

电子文件怎么盖章?

电子文件怎么盖章&#xff1f;电子文件盖章是数字化办公中常见的操作&#xff0c;包括盖电子公章和电子骑缝章。以下是针对这两种情况的详细步骤&#xff1a; 一、盖电子公章 方法一&#xff1a;使用专业软件 选择软件&#xff1a;选择一款专业的电子签名或PDF编辑软件&…...

IDEA在编译的时候报Error: java: 找不到符号符号: 变量 log lombok失效问题

错误描述 idea因为lombok的报错: java: You arent using a compiler supported by lombok, so lombok will not work and has been disabled.Your processor is: com.sun.proxy.$Proxy8Lombok supports: sun/apple javac 1.6, ECJ 原因&#xff1a;这是由于Lombok的版本过低的…...

shell脚本--常见案例

1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件&#xff1a; 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

DockerHub与私有镜像仓库在容器化中的应用与管理

哈喽&#xff0c;大家好&#xff0c;我是左手python&#xff01; Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库&#xff0c;用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件

今天呢&#xff0c;博主的学习进度也是步入了Java Mybatis 框架&#xff0c;目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学&#xff0c;希望能对大家有所帮助&#xff0c;也特别欢迎大家指点不足之处&#xff0c;小生很乐意接受正确的建议&…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例

文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

GitFlow 工作模式(详解)

今天再学项目的过程中遇到使用gitflow模式管理代码&#xff0c;因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存&#xff0c;无论是github还是gittee&#xff0c;都是一种基于git去保存代码的形式&#xff0c;这样保存代码…...

FFmpeg:Windows系统小白安装及其使用

一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】&#xff0c;注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录&#xff08;即exe所在文件夹&#xff09;加入系统变量…...

R 语言科研绘图第 55 期 --- 网络图-聚类

在发表科研论文的过程中&#xff0c;科研绘图是必不可少的&#xff0c;一张好看的图形会是文章很大的加分项。 为了便于使用&#xff0c;本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中&#xff0c;获取方式&#xff1a; R 语言科研绘图模板 --- sciRplothttps://mp.…...

【堆垛策略】设计方法

堆垛策略的设计是积木堆叠系统的核心&#xff0c;直接影响堆叠的稳定性、效率和容错能力。以下是分层次的堆垛策略设计方法&#xff0c;涵盖基础规则、优化算法和容错机制&#xff1a; 1. 基础堆垛规则 (1) 物理稳定性优先 重心原则&#xff1a; 大尺寸/重量积木在下&#xf…...

小木的算法日记-多叉树的递归/层序遍历

&#x1f332; 从二叉树到森林&#xff1a;一文彻底搞懂多叉树遍历的艺术 &#x1f680; 引言 你好&#xff0c;未来的算法大神&#xff01; 在数据结构的世界里&#xff0c;“树”无疑是最核心、最迷人的概念之一。我们中的大多数人都是从 二叉树 开始入门的&#xff0c;它…...

【WebSocket】SpringBoot项目中使用WebSocket

1. 导入坐标 如果springboot父工程没有加入websocket的起步依赖&#xff0c;添加它的坐标的时候需要带上版本号。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dep…...