`
abruzzi
  • 浏览: 444716 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

C语言插件机制(下)

阅读更多

前言

上一篇文章简单介绍了*NIX下的动态库的使用,我们在这篇文章中实现一个计算器,计算器程序calc本身不做运算,只是将操作数传递给具体的插件(adder, suber, muler, diver)来完成实际运算。首先,计算器根据插件配置文件plugin.xml来确定插件的位置,名称,入口符号的定义,然后依次调用各个插件完成计算。

 

插件列表

文中涉及到的插件定义在plugin.xml中,文档结构如下:

 

<plugins>
    <plugin name="adder">
        <library path="/home/juntao/.libs/adder.so">
        </library>
        <entry name="add">
        </entry>
    </plugin>
    <plugin name="suber">
        <library path="/home/juntao/.libs/suber.so">
        </library>
        <entry name="sub">
        </entry>
   </plugin>
   <plugin name="muler">
        <library path="/home/juntao/.libs/muler.so">
        </library>
        <entry name="mul">
        </entry>
   </plugin>
   <plugin name="diver">
        <library path="/home/juntao/.libs/diver.so">
        </library>
        <entry name="div">
        </entry>
   </plugin>
</plugins>

 

每个插件为一个plugin标签,plugin标签中包含library, entry两个字标签,分别定义动态库文件的路径及名称和插件函数的入口。为了简便,我们不重复设计list及xml解析,这里使用libxml2作为xml的分析器,GLIB中的GSList(单链表)来作为插件列表的链表对象。

 

每一个插件在C语言中的定义如下,非常简单(plugin.h)

 

#ifndef _PLUGIN_H_
#define _PLUGIN_H_

typedef struct{
    char name[64];
    char path[256];
    char entry[128];
    int version;
}Plugin;

#endif

 

这里为了行文方便,Plugin结构中的字符串为静态尺寸。

 

计算器 

计算器调用parseconf模块中的load_plugins将plugin.xml中定义的Plugin加载进一个GSList,以备后用:

 

#include "plugin.h"

extern int load_plugins(char *config, GSList **list);

 

插件中的函数原型应该符合接口定义:

 

//pointer to function, which return a double, and get 2 double as input
double (*pfunc)(double a, double b);

 

计算器的主要代码如下:

int calc_test(double a, double b){
    GSList *list = NULL, *it = NULL;
    Plugin *pl = NULL;
    
    //insert a null node into list at first
    list = g_slist_append(list, NULL);
    
    int code = 0;
    double result;

    //load plugin defined in plugin.xml into list
    load_plugins("plugin.xml", &list);
    
    for(it = list; it != NULL; it = it->next){
        pl = (Plugin *)it->data;
        if(pl == NULL){
            continue;
        }else{
            //open the library
            flib = dlopen(pl->path, RTLD_LAZY);
            dlError = dlerror();

            if(dlError){
                fprintf(stderr, "open %s failed\n", pl->name);
                g_slist_free(list);
                return -1;
            }
            
            //get the entry
            *(void **)(&pfunc) = dlsym(flib, pl->entry);
            dlError = dlerror();
            if(dlError){
                fprintf(stderr, "find symbol %s failed\n", pl->entry);
                g_slist_free(list);
                return -1;
            }

            //call the function
            result = (*pfunc)(a, b);
            printf("%s(%f, %f) = %f\n", pl->entry, a, b, result);
            
            //then close it
            code = dlclose(flib);
            dlError = dlerror();

            if(code){
                fprintf(stderr, "close lib error\n");
                g_slist_free(list);
                return -1;
            }
        }
    }
    
    g_slist_free(list);
    return 0;
}

 

首先,定义一个GSList,然后将其传递给load_plugins,load_plugins解析plugin.xml,然后填充list返回,calc_test遍历插件列表,并调用每一个插件定义的entry.

 

除法器

 我们来看一个具体的插件:做除法的模块

 

#include <stdio.h>

double div(double a, double b){
    if(b == 0){
        fprintf(stderr, "div zero error\n");
        return -1;
    }else{
        return a / b;
    }
}

diver.c在编译之后,生成diver.so,将其置于plugin.xml定义的位置处即可。

 

运行结果如下图所示:


其他代码如xml的解析,GSList的使用等与插件机制关系不大,感兴趣的朋友可以在附件中查看。

 

  • 大小: 14.5 KB
分享到:
评论
10 楼 sinoyster 2010-09-12  
我们就是这样在做,思路和楼主差不多
9 楼 phoenixup 2010-09-10  
这个有点意思~~
8 楼 abruzzi 2010-09-05  
sunday1207 写道
这个列子里动态库的参数只能有两个,是否有必要把参数也配置话呢

va_args,或者结构体如下形式:

typedef struct{
void *data;
unsigned int length;
}data_t;

这样,在dl*函数内部可以通过判断length来判断真正的数据长度。这个只是程序实现上的技巧。
7 楼 abruzzi 2010-09-05  
mallon 写道
但是很多场合下函数原型不可能固定的啊...

主要看接口的定义了,一般而言,接口这种东西,设计好之后就很少变化了。如果你所说的函数原型不固定,那么有很多方式来解决,如va_args,结构体数据等。
6 楼 sunday1207 2010-09-04  
这个列子里动态库的参数只能有两个,是否有必要把参数也配置话呢
5 楼 mallon 2010-09-03  
但是很多场合下函数原型不可能固定的啊...
4 楼 mxswl 2010-09-03  
和vm比较的话,感觉
差别:静态编译
共同点:主动的动态链接.
3 楼 abruzzi 2010-09-02  
smzd 写道
放眼望去皆动态啊!

这个主要看如何权衡了,动态的好处是松耦合,大家面向接口写程序,效率较静态的肯定会低一些。这个例子当然完全可以用静态的实现,但是如果应用较复杂,而对效率要求不是很高的话,可以考虑向动态转。不过话又说回来了,现在代码的执行效率,要求貌似已经不那么严格了,看看现在的Java应用有多少,呵呵。
2 楼 raojl 2010-09-02  
思路挺好的。
1 楼 smzd 2010-09-02  
放眼望去皆动态啊!

相关推荐

    C语言插件机制(下) 转

    NULL 博文链接:https://sealbird.iteye.com/blog/756577

    c语言华容道源码.rar

    它包含了完整的游戏逻辑和界面设计,可以帮助我们深入理解华容道的运行机制,以及如何在计算机程序中实现这种机制。这份资料包的内容丰富,包括了华容道游戏的初始化、方块的移动、判断游戏是否胜利等核心功能。同时...

    c语言图书借阅系统源码.rar

    同时,该系统可能还包括了错误处理机制,让用户能够更好地理解如何确保程序的健壮性和稳定性。对于正在学习C语言编程的学生来说,通过分析和运行这个图书借阅系统的源码,可以加深对C语言语法的理解,提升编程技巧,...

    c语言学生成绩管理系统源码 + 运行程序

    此外,系统还考虑到了数据的安全性和完整性,通过适当的错误处理和验证机制,确保了数据的准确性和可靠性。 值得一提的是,这套C语言学生成绩管理系统源码资源不仅具有高度的实用性,还具备很强的可扩展性和可定制...

    课程作业-基于epoll机制的高并发聊天室,c语言实现+源代码+文档说明

    基于epoll机制的高并发聊天室,c语言实现 - 不懂运行,下载完可以私聊问,可远程教学 该资源内项目源码是个人的毕设,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! 1、该资源内...

    基于epoll机制的高并发聊天室c语言实现代码.zip

    相比非阻塞忙轮询这类无差别轮训,linux内核提供了epoll这样更高级的形式 把需要处理的IO事件添加到epoll内核列表,epoll_wait来监控并提醒用户程序当IO事件发生时 此聊天室客户端代码fork两个进程,子进程把用户...

    c语言 条形码识别实例代码

    以下是对C语言条形码识别的描述,不包含具体的代码实现: 图像处理:条形码识别首先需要对输入的图像进行预处理。这包括图像的二值化、去噪和增强等操作,以提高条形码的边缘清晰度和对比度。 条形码定位:在...

    c语言-球球大作战软件

    吞噬成长机制:通过吞噬地图中的小颗粒使球球不断变大,以达成更高分数。 ai小球设置:地图内设有多个ai小球,它们可以根据自身的大小和与玩家的距离来选择追击玩家或者逃跑,增加游戏的趣味性。 积分系统:设立...

    c语言种地要浇水游戏源码

    4. **游戏机制与玩法**: - 玩家需要定时给作物浇水,保持土壤湿润度。 - 可能包含升级系统,如改进灌溉设备以提高浇水效率。 - 游戏内可能设有任务系统,完成任务获得奖励或解锁新作物。 - 可能存在经济系统,...

    基于SSM和VUE的C语言试题生成与考试系统(免费提供全套java开源项目源码+论文)

    Spring框架负责业务逻辑处理,通过SpringMVC实现高效的请求处理机制。 MyBatis用于数据库操作,简化数据持久化过程,提高系统性能。 实现RESTful API,确保前后端分离,提高系统的可维护性和可扩展性。 数据库设计:...

    c语言自创推箱子游戏改版源码

    游戏保留了经典推箱子游戏的核心玩法,即推动箱子到指定位置,但在此基础上加入了众多创新元素和机制,使得游戏更加丰富和有趣。 二、核心玩法与特色 多样化的关卡设计:每个关卡都有独特的布局和难度,需要玩家运用...

    基于C语言实现的坦克游戏源代码.zip

    设计敌方坦克生成和控制机制,包括生成位置、难度递增等。 实现碰撞检测,包括坦克与子弹、坦克与障碍物等的碰撞判断。 关卡设计: 设计关卡地图,包括障碍物的位置、敌方坦克的生成等。 设计关卡目标和胜利条件,...

    C语言实现基于Risc-V 的操作系统内核模拟设计与实现源代码,一个运行在RISC-V架构处理器上的玩具嵌入式操作系统

    C语言实现基于Risc-V 的操作系统内核模拟设计与实现源代码,一个运行在RISC-V架构处理器上的玩具嵌入式操作系统 完成了操作系统的引导、UART 串口驱动、中断管理、动态内存管理、多任务调度、自旋锁、信号量、FAT32...

    ASP基于Web的C语言教学系统的研究与实现.zip

    其特点包括清晰的代码结构、高效的数据库访问、安全的用户认证和授权机制、响应式布局以适应不同设备、友好的用户界面等。这些项目源码还提供了丰富的功能模块和插件,支持用户管理、权限控制、数据可视化、电子支付...

    C语言嵌入式Linux编程第3期:程序的编译、链接和运行

    本课程为《C语言嵌入式Linux编程》第3期,主要对程序的编译、链接及运行机制进行分析。同时对静态库链接、动态链接的过程、插件原理、内核模块运行机进行探讨,后对嵌入式系统比较难理解的u-boot重定位、u-boot加载...

    Lua 入门教程

    Lua 教程 lua Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用...扩展和数据库插件如:MySQL Proxy 和 MySQL WorkBench 安全系统,如入侵检测系统

    摘录自FastDFS的高性能网络通信框架 .rar

    FastDFS为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,使用FastDFS很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。 FastDFS架构  FastDFS架构...

    Ceedling:基于RubyRake的C项目构建和测试系统

    Ceedling还可以通过方便的插件机制进行扩展。 使用说明文件 文档和许可证信息存在 入门 首先,请确保Ruby已安装在您的系统上(如果尚未安装)。 然后,在命令提示符下: &gt; gem install ceedling (为打算成为开发...

    java基础学习笔记 java整合技术 java工具类.rar

    健壮性:java的健壮性与自动垃圾回收机制有关,自动垃圾回收机制简称GC机制,java语言运行过程中产生的垃圾是自动回收的,不需要程序员关心。 可移植性:java程序可以做到一次编译,到处运行。在Windows操作系统上...

    UML State Machine Wizard VC Addin 7.0

    UML StateWizard for VS.NET/VC6/EVC4可为嵌入式系统或Win32/WinCE开发带来可视化、基于可移植C语言的UML状态机编程机制。同时,作为Visual C++的插件,它使得开发者可以在强大的Visual C++开发环境中进行嵌入式系统...

Global site tag (gtag.js) - Google Analytics