zoukankan      html  css  js  c++  java
  • Matlab调用C程序 分类: Matlab c/c++ 2015-01-06 19:18 464人阅读 评论(0) 收藏

    Matlab是矩阵语言,如果运算可以用矩阵实现,其运算速度非常快。但若运算中涉及到大量循环,Matlab的速度令人难以忍受的。当必须使用for循环且找不到对应的矩阵运算来等效时,可以将耗时长的函数用C语言实现,并编译成Mex文件,Matlab便可以像调用内建函数一样调用C编写的函数。Mex文件其实是一种动态链接库,旧版本Matlab可以直接调用.dll,新版本要调用.mexw32或.mexw64文件。

    编译过程需要C语言编译器,在Matlab中键入mex –setup进行安装与配置。

    MEX文件的源代码组成

    (1)功能子程序。该过程包含了Mex文件实现计算功能的代码,是标准的C语言子程序。

    (2)入口子程序。该过程提供功能子程序与Matlab之间的接口,以mexFunction函数实现。注意,入口过程的名称必须是mexFunction,并且包含四个参数,即

    void mexFunction(int nlhs,mxArray*plhs[],int nrhs,const mxArray *prhs[]);

    nrhs(left hand side): 输入参数的个数;

    prhs是一个输入数组,其内容为指针,指向mxArray类型的数据(MATLAB中所有数据都是以矩阵的形式mxArray保存的)。

    nlhs, plhs含义类似。

    具体地,若在Matlab中执行[a,b]=test(c,d,e) ,则nlhs=2, nrhs=3,prhs[0]指向c,prhs[1]指向d,prhs[2]指向e(可以理解为:prhs[0]=&c, prhs[1]=&d, prhs[2]=&e),注意prhs是const指针数组,故不能改变其指向内容;函数返回时将plhs[0],plhs[1]指向的内容赋给a,b(可以理解为a=*plhs[0], b=*plhs[1])。

    :新建add.c,源码如下:

    #include "mex.h"  
    double add(double x, double y)
    {
        return x + y;
    } 
    void mexFunction(int nlhs,mxArray *plhs[], int nrhs,const mxArray *prhs[])
    {
        double *a;
        double b, c;
        plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL);
        a = mxGetPr(plhs[0]);
        b = *(mxGetPr(prhs[0]));
        c = *(mxGetPr(prhs[1]));
        *a = add(b, c);
    }
    

    将add.c拷贝至Matlab当前目录,执行mex add.c,生成add.mexw64,该文件实现求和功能。此时便可在Matlab中调用该函数:

    >> output = add(1.1, 2.2); 

    分析:

    #include "mex.h"

    Mex源文件必须包含mex.h,该头文件提供了大量Matlab与C(或Fortran)语言的之间的接口函数,函数前缀有mex-和mx-两种,带mx-前缀的大多是对mxArray数据进行操作的函数,如mxIsDouble,mxCreateDoubleMatrix等;而带mex-前缀的则大多是与Matlab环境进行交互的函数,如mexPrintf,mexErrMsgTxt等。具体可参考Apiref.pdf

    plhs[0] = mxCreateDoubleMatrix(1, 1,mxREAL);

    建立一个1x1的double类型的矩阵,返回刚建立的mxArray的地址,赋给指针plhs[0];

    a = mxGetPr(plhs[0]);

    返回指针plhs[0]所指向矩阵的第一个实数的地址,并赋给a;

    b = *(mxGetPr(prhs[0]));

    获取指针prhs[0]指向矩阵的第一个实数,并赋给b;

    *a = add(b, c);

    调用C程序add,计算b,c之和并赋给a指向的内容;

    例:新建myhilb.c,源码如下:

    #include "mex.h"
    void myhilb(double *y,int n)
    {
        int i,j;
        for(i=0;i<n;i++)
            for(j=0;j<n;j++)
                *(y+j+i*n)=1/((double)i+(double)j+1);
    }
    void mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[])
    {
        double x,*y;   
        if (nrhs!=1)
            mexErrMsgTxt("One inputs required.");
        if (!mxIsDouble(prhs[0])||mxGetN(prhs[0])*mxGetM(prhs[0])!=1)
            mexErrMsgTxt("Input must be scalars.");
        x=mxGetScalar(prhs[0]);
        plhs[0]=mxCreateDoubleMatrix(x,x,mxREAL);
        y=mxGetPr(plhs[0]);
        myhilb(y,(int)x);
    }
    

    将myhilb.c拷贝至Matlab当前目录,执行mex myhilb.c,生成myhilb.mexw64,该文件实现了计算Hilbert矩阵的功能(Hilbert矩阵:H(i,j)=1/(i+j-1))。

    此时便可在Matlab中调用该函数:

    >> output = myhilb (6);

    分析:

    mexFunction中进行了参数检查,函数mexErrMsgTxt显示出错信息后即退回到MATLAB。

    mxGetScalar:获取输入矩阵第一个元素的实数部分;mxGetM:获取矩阵的行数。

    为了测试一下Mex文件与m文件的速度差异,编写m文件并运行之:

    tic
    m=10000;
    a=zeros(m,m);
    for i=1:m
         for j=1:m
             a(i,j)=1/(i+j);
         end
    end
    toc
    

    结果:Elapsed time is3.620924 seconds.

    接着运行Mex文件

    tic
    output = myhl(10000);
    toc

    结果:Elapsed timeis 0.730596 seconds.

    可以看出Mex文件与M文件速度差异很大。

    VS2010生成Mex文件(本人64位操作系统)

    上述利用Matlab编译生成Mex文件,同样也可以使用VS2010生成Mex文件,只不过需要对VS环境进行配置,过程如下:

    1、  新建一个win32 控制台的dll 空项目”myhilb”;

    2、  新建源文件myhilb.c,将上述myhilb.c内容拷进即可;

    3、  添加.def文件,内容为:

    LIBRARY

    EXPORTSmexFunction

    4、  配置项目属性, 打开项目属性配置页:

    (1)C/C++—>常规—>附加包含目录,输入matlab下安装目录下externinclude

    本人输入E:Matlab2010Installexterninclude

    (2)链接器->常规—>附加库目录,输入matlab下安装目录下externlibwin64microsoft

    本人输入E:Matlab2010Installexternlibwin64microsoft

    (3)连接器 ->输入->附加依赖项,输入

    libmx.lib

    libeng.lib

    libmat.lib

    libmex.lib

    (4)链接器->常规—>输出文件,输入$(OutDir)$(TargetName).mexw64(若此处不更改,可在生成dll文件后将后缀名改为mexw64即可,这也验证了Mex实际上就是DLL,只是后缀名不同罢了)

    (5)链接器->高级—>目标计算机,设为MachineX64(32位系统不用更改)

    设置好点击应用,执行了(5)的64位系统还需要在执行:

    生成—>配置管理器—>活动解决平台,改为x64

    5、按F7编译工程,会在Debug下生成.mexw64文件,如下图:


    VS中单步调试Mex文件

    在Matlab环境下使用 mex  –g myhilb.c命令进行调试,但无法加断点进行单步调试,故需转到VS环境下调试。

    不管是利用VS还是利用Matlab生成Mex文件,只要有c源文件和Mex文件就可以利用VS对Mex源程序加断点进行单步调试(我们用上面myhilb.c和myhilb.mexw64做测试)。

    1、将Matlab当前目录改为Mex文件(C文件)所在目录;

    2、在VS2010中打开C文件,调试—>附加到进程,附加MATLAB.exe;

    3、VS中在C源码中添加断点,在Matlab命令窗口调用Mex文件提供的接口;

    如Matlab执行:out=myhilb(6);



    此时,VS2010中便可按F10进行单步调试:


    要说明的是,在调试阶段Matlab处于假死状态,另外,Matlab调用了Mex文件后需要执行clear all命令后才能删除Mex文件;

    同样地,若利用VS生成Mex文件后直接将Matlab当前目录改至Debug目录进行调试,则调试完必须执行clear all指令才能重新编译工程。

    参考:

    http://blog.sina.com.cn/s/blog_468651400100coas.html

    http://www.cppblog.com/xiaozhixd/articles/108490.html

    http://www.linuxidc.com/Linux/2012-08/68148.htm

    http://blog.sina.com.cn/s/blog_a7e72e940101cti9.html

    http://blog.csdn.net/raodotcong/article/details/6317273


    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    MySQL 4.1x 中文乱码效果
    linux内核中的“捏造化”
    Ubuntu开发者峰会在布拉格举行
    Decode 函数的用法
    Solaris 10拆卸jdk1.6及点窜成默许JDK
    教你编写高机能的mysql语法
    DirectShow9.0在vs2005中存在的问题解决
    Unicode,unicoidebig,Asci,UTF8文件read和write
    自已写了个GDI类,实现了相对路径载入任意类型的图片函数,并加一个在CRECT矩形上贴图的函数(5月25日写)
    两种解析EDIT控件上文本的方式
  • 原文地址:https://www.cnblogs.com/luo-peng/p/4646225.html
Copyright © 2011-2022 走看看