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


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

  • 相关阅读:
    win7网络共享原来如此简单,WiFi共享精灵开启半天都弱爆了!
    JQUERY UI Datepicker Demo
    Official online document, install svn server in centOS
    JAVE not work in linux
    AMR 转mp3 失败
    XD, XR, DR 股票
    Linux 下MySql 重置密码
    Difinition Of Done
    Apache, Tomcat, JK Configuration Example
    Linux 安装tomcat
  • 原文地址:https://www.cnblogs.com/luo-peng/p/4646225.html
Copyright © 2011-2022 走看看