`
sealbird
  • 浏览: 570924 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

C语言插件机制(下) 转

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



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




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>  

<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)




C代码
#ifndef _PLUGIN_H_   
#define _PLUGIN_H_   
  
typedef struct{   
    char name[64];   
    char path[256];   
    char entry[128];   
    int version;   
}Plugin;   
  
#endif  

#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,以备后用:




C代码
#include "plugin.h"   
  
extern int load_plugins(char *config, GSList **list);  

#include "plugin.h"

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

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




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

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


计算器的主要代码如下:


C代码
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;   
}  

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.



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




C代码
#include <stdio.h>   
  
double div(double a, double b){   
    if(b == 0){   
        fprintf(stderr, "div zero error\n");   
        return -1;   
    }else{   
        return a / b;   
    }   
}  

#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的使用等与插件机制关系不大,感兴趣的朋友可以在附件中查看。


分享到:
评论

相关推荐

    c语言华容道源码.rar

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

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

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

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

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

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

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

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

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

    c语言-球球大作战软件

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

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

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

    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 安全系统,如入侵检测系统

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

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

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

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

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

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

    UML State Machine Wizard VC Addin 7.0

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

    Tcl_TK编程权威指南pdf

    本书共分为55章,依次详细讲述了Tcl基础、Tcl高级特性、TK基础、TK组件、TK详解、C语言编程、各版本之间的差异等方面的知识,并通过大量实例,生动翔实地向读者介绍了Tcl/Tk编程,是读者掌握Tcl/Tt的必备参考书。...

    YodPHP 1.4.1.zip

    emmt扩展加载机制优化;编辑器markdown多光标编辑,支持关联工具栏快捷功能;aero效果支持,登录界面优化;其他优化:文件名超出部分...表示;正在上传、远程下载关闭页面提醒。fix bug安全漏洞修复:文件越权读取...

Global site tag (gtag.js) - Google Analytics