首页 > 代码库 > Matlab调用C程序
Matlab调用C程序
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下安装目录下\extern\include
本人输入E:\Matlab2010\Install\extern\include
(2)链接器->常规—>附加库目录,输入matlab下安装目录下\extern\lib\win64\microsoft
本人输入E:\Matlab2010\Install\extern\lib\win64\microsoft
(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
Matlab调用C程序