编写MatlabmexFunction(Cmex)
资料⼀ MATLAB的MEX⽂件编写和调试
1. MEX的编写格式
写MEX程序其实就是写⼀个DLL程序,所以你可以使⽤C,C++,Fortran等多种编程语⾔来写。
编写MEX程序的编辑器可以使⽤MATLAB的代码编辑器,也可使⽤⾃⼰的C++编辑器,如VS2008等。
⽤MATLAB的编辑器的好处是,MEX函数会加粗⾼亮显⽰,这给程序编写带来便利,可惜⽆法动态调试。如⽤VC即可编译也可调试,⽐较⽅便。mex的编译结果实际上就是⼀个带输出函数mexFunction 的dll⽂件,所以会⽤VC编写和调试dll,就会⽤VC编写和调试MEX程序。
a. MEX⽂件格式
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] )
{
}
四个参数分别⽤来输出和输⼊数据: nlhs 输出参数个数,plhs 输出参数指针 (nrhs和prhs是输⼊参数相关的)。
注意: 我们对输出和输⼊参数的操作都是通过指针的⽅式进⾏的。(这点很容易理解,因为我们的计算结果是需要传递给MATLAB的,实际上我们传递的不是数据,⽽是指针。MATLAB可以通过这些指针,访问内存中的数据。)
b. 操作输⼊数据
对输⼊数据进⾏操作,需要通过MEX函数mxGetPr 得到数据的指针地址。 mxGetM 和 mxGetN 得到矩阵数据的⾏和列 (返回整数)。对于实矩阵,我们可以定义 double *M; 来对实矩阵数据操作(不过似乎是,plhs, prhs都是指向double类型的指针,所以下⾯的这个M等,都要定义成double*类型的)。如:
double *M;
int m, n;
M = mxGetPr(prhs[0]); // 指针指向第⼀个参数的数据地址
m = mxGetM(prhs[0]);
n = mxGetN(prhs[0]);
需要注意的是,MATLAB矩阵数据的存储顺序是"从上到下,从左到右"。也就是说对于MATLAB的m x n的矩阵A。 A(1,1) 就是 *M,A(2,1)就是 *(M+1) ,以此类推,A(i, j) 就是 *(M + m*(j-1) + (i-1)).
注意: MATLAB的指标从1开始,C的指标从0开始。
c. 输出数据操作
对于输出数据,我们需要⾸先分配内存空间,有专门的mex函数可以使⽤,如:
plhs[0] = mxCreateDoubleMatrix(m, n, mxREAL); //⽣成m x n 的实矩阵。
同输⼊数据⼀样,要对输出数据操作,我们也需要⼀个指向数据的指针变量,如
double *A;
A = mxGetPr( plhs[0]);
下⾯介绍⼀下如何使⽤VS2008编写MEX并编译调试。
2. VC中编写MEX
打开Visual Studio 2008/2010/2012/2013, 新建项⽬, 选择MFC DLL.
a. 配置项⽬属性
打开项⽬属性配置页,选择配置属性⽬录,然后分别进⾏如下操作
VC++⽬录 -> 包含⽬录加⼊MATLAB安装⽬录下的 \extern\include 路径。
VC++⽬录 -> 库⽬录加⼊MATLAB的 \extern\lib\win32\microsoft 路径。
连接器 -> 输⼊ -> 附加依赖项输⼊libmx.lib libeng.lib libmat.lib libmex.lib
b. 编辑输出函数
在项⽬源⽂件的. def 中EXPORTS段加⼊mexFunction,如:
EXPORTS ; 此处可以是显式导出 mexFunction
c. 编写MEX⽂件
项⽬⽂件中新建⼀个C++⽂件如 mexproc.cpp,⾥⾯按前⾯介绍的格式编写代码即可。
d. VC编译MEX
像编译其他程序那样直接编译即可,成功会⽣成dll⽂件。如果编译链接时出错,根据错误提⽰,检查⼀下lib和h的路径是否正确,有⽆缺少lib⽂件,代码是否有语法错误等。
3. VC中调试MEX
要调试MEX程序就要先编译,再调⽤它。所以我们需要在MATLAB中调⽤这个函数,并在VC的MEX程序相应位置处下断点即可。调⽤的函数名就是dll的主⽂件名,你可以根据⾃⼰的需要改名。
我们⽤mymexfun.dll为例,先在VC的 mexFunction 函数代码段开始处F9下断。然后Ctrl+Alt+P附加进程。这样就可以运⾏命令调试程序了。我们可以在MATLAB的命令⾏⾥输⼊命令:
[输出变量] = mymexfun(输⼊变量)
程序⼀旦被调⽤,就会被断在我们的断点处。接着你就可以像调试C++程序那样调试MEX程序了。(如果命令不到,检查⼀下matlab当前路径,和path路径。)
在MATLAB中编译MEX可以输⼊: mex ⽂件名.cpp
MATLAB上编译MEX时,你可以选择不同的编译器如lc, gcc等。也可以在编译时附加lib和h⽂件。关于mex的命令详解请参考MATLAB帮助⽂档。
资料⼆深⼊
在使⽤MATLAB编译C/C++代码时,C/C++代码中要使⽤⼀个mexFunction函数,那么这个函数是如何定义,在编译时⼜是如何实现的呢?下⾯我将使⽤实例进⾏说明。
如⼀个简单的函数:
double add(double x, double y)
{
return x + y;
}
mexFunction的定义为:
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
}
可以看到,mexFunction是没返回值的,它不是通过返回值把结果传回Matlab的,⽽是通过对参数plhs的赋值。mexFunction的四个参数皆是说明Matlab调⽤MEX⽂件时的具体信息,如这样调⽤函数时:
>> b = 1.1; c = 2.2;
>> a = add(b, c)
mexFunction四个参数的意思为:
nlhs = 1,说明调⽤语句左⼿⾯(lhs-left hand side)有⼀个变量,即a。
nrhs = 2,说明调⽤语句右⼿⾯(rhs-right hand side)有两个⾃变量,即b和c。
plhs是⼀个数组,其内容为指针,该指针指向数据类型mxArray。因为现在左⼿⾯只有⼀个变量,即该数组只有⼀个指针,plhs[0]指向的结果会赋值给a。
prhs和plhs类似,因为右⼿⾯有两个⾃变量,即该数组有两个指针,prhs[0]指向了b,prhs[1]指向了c。要注意prhs是const的指针数组,即不能改变其指向内容。
因为Matlab最基本的单元为array,⽆论是什么类型也好,如有double array、 cell array、 struct array…
…所以a,b,c都是array,b = 1.1便是⼀个1x1的double array。⽽在C语⾔中,Matlab的array使⽤mxArray类型来表⽰。所以就不难明⽩为什么plhs和prhs都是指向mxArray 类型的指针数组。
完整的add.c如下:
#include "mex.h"//使⽤mex⽂件必须包含头⽂件
//执⾏具体⼯作的C函数
double add(double x, double y)
{博客为什么没人用了
return x+y;
}
//MEX⽂件接⼝函数
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, 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);
}
mexFunction的内容是什么意思呢?我们知道,如果这样调⽤函数时:
>> output = add(1.1, 2.2);
在未涉及具体的计算时,output的值是未知的,是未赋值的。所以在具体的程序中,我们建⽴⼀个1x1
的实double矩阵(使⽤mxCreateDoubleMatrix函数,其返回指向刚建⽴的mxArray的指针),然后令plhs[0]指向它。接着令指针a指向plhs [0]所指向的mxArray的第⼀个元素(使⽤mxGetPr函数,返回指向mxArray的⾸元素的指针)。同样地,我们把prhs[0]和prhs [1]所指向的元素(即1.1和2.2)取出来赋给b和c。于是我们可以把b和c作⾃变量传给函数add,得出给果赋给指针a所指向的mxArray中的元素。因为a是指向plhs[0]所指向的mxArray的元素,所以最后作输出时,plhs[0]所指向的mxArray赋值给output,则 output便是已计算好的结果了。
实际上mexFunction是没有这么简单的,我们要对⽤户的输⼊⾃变量的个数和类型进⾏测试,以确保输⼊正确。如在add函数的例⼦中,⽤户输⼊char array便是⼀种错误了。
从上⾯的讲述中我们总结出,MEX⽂件实现了⼀种接⼝,把C语⾔中的计算结果适当地返回给Matlab罢了。当我们已经有⽤C编写的⼤型程序时,⼤可不必在 Matlab⾥重写,只写个接⼝,做成MEX⽂件就成了。另外,在Matlab程序中的部份计算瓶颈(如循环),可通过MEX⽂件⽤C语⾔实现,以提⾼计算速度。
⼀个简单的MEX⽂件例⼦:⽤m⽂件建⽴⼀个1000×1000的Hilbert矩阵。
% mextest.m
tic
m=1000;
n=1000;
a=zeros(m,n);
for i=1:1000
for j=1:1000
a(i,j)=1/(i+j);
end
end
toc
在matlab中新建⼀个Matlab_1.cpp ⽂件并输⼊以下程序:
#include "mex.h"
/
/该函数是mexfunction调⽤的唯⼀⼀个计算⼦程序
void hilb(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;
int n;
if (nrhs!=1)
mexErrMsgTxt("One inputs required.");
if (nlhs != 1)
mexErrMsgTxt("One output 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);
n=mxGetM(plhs[0]);
y=mxGetPr(plhs[0]);
hilb(y, n);
}
该程序是⼀个C语⾔程序,它也实现了建⽴Hilbert矩阵的功能。在MATLAB命令窗⼝输⼊以下命令:mex Matlab_1.cpp,即可编译成功。进⼊该⽂件夹,会发现多了⼀个⽂件:w32,其中w32即是MEX⽂件。运⾏下⾯程序:
tic
a=Matlab_1(1000);
toc
由上⾯实验看出,同样功能的MEX⽂件⽐m⽂件快得多。
MEX⽂件的组成与参数
MEX⽂件的源代码⼀般由两部分组成:
(1)计算过程。该过程包含了MEX⽂件实现计算功能的代码,是标准的C语⾔⼦程序。
(2)⼊⼝过程。该过程提供计算过程与MATLAB之间的接⼝,以⼊⼝函数mxFunction实现。在该过程中,通常所做的⼯作是检测输⼊、输出参数个数和类型的正确性,然后利⽤mx-函数得到MATLAB传递过来的变量(⽐如矩阵的维数、向量的地址等),传递给计算过程。
MEX⽂件的计算过程和⼊⼝过程也可以合并在⼀起。但不管那种情况,都要包含#include "mex.h",以保证⼊⼝点和接⼝过程的正确声明。注意,⼊⼝过程的名称必须是mexFunction,并且包含四个参数,即:
void mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[])
其中,参数nlhs和nrhs表⽰MATLAB在调⽤该MEX⽂件时等式左端和右端变量的个数,例如在MATLAB命令窗⼝中输⼊以下命令:
[a,b,c]=Matlab_1(d,e,f,g)
则nlhs为3,nrhs为4。
MATLAB在调⽤MEX⽂件时,输⼊和输出参数保存在两个mxArray*类型的指针数组中,分别为prhs[]和plhs[]。prhs[0]表⽰第⼀个输⼊参数,prhs[1]表⽰第⼆个输⼊参数,…,以此类推。如上例中,d→prhs[0],e→prhs[1],f→prhs[2],f→prhs[3]。同时注意,这些参数的类型都是mxArray *。
接⼝过程要把参数传递给计算过程,还需要从prhs中读出矩阵的信息,这就要⽤到下⾯的mx-函数和mex-函数。
第三部分 MEX函数
1 MEX⽂件的组成与参数
MEX⽂件的源代码⼀般由两部分组成:
(1)计算过程。该过程包含了MEX⽂件实现计算功能的代码,是标准的C语⾔⼦程序。
(2)⼊⼝过程。该过程提供计算过程与MATLAB之间的接⼝,以⼊⼝函数mxFunction实现。在该过程中,通常所做的⼯作是检测输⼊、输出参数个数和类型的正确性,然后利⽤mx-函数得到MATLAB传递过来的变量(⽐如矩阵的维数、向量的地址等),传递给计算过程。
MEX⽂件的计算过程和⼊⼝过程也可以合并在⼀起。但不管那种情况,都要包含#include "mex.h",以保证⼊⼝点和接⼝过程的正确声明。注意,⼊⼝过程的名称必须是mexFunction,并且包含四个参数,即:
void mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[])
其中,参数nlhs和nrhs表⽰MATLAB在调⽤该MEX⽂件时等式左端和右端变量的个数,例如在MATLAB命令窗⼝中输⼊以下命令:
[a,b,c]=Matlab_1(d,e,f,g)
则nlhs为3,nrhs为4。
MATLAB在调⽤MEX⽂件时,输⼊和输出参数保存在两个mxArray*类型的指针数组中,分别为prhs[]和plhs[]。prhs[0]表⽰第⼀个输⼊参数,prhs[1]表⽰第⼆个输⼊参数,…,以此类推。如上例中,d→prhs[0],e→prhs[1],f→prhs[2],f→prhs[3]。同时注意,这些参数的类型都是mxArray *。
接⼝过程要把参数传递给计算过程,还需要从prhs中读出矩阵的信息,这就要⽤到下⾯的mx-函数和mex-函数。
2 常⽤的mex-函数和mx-函数
在MATLAB6.5版本中,提供的mx-函数有106个,mex-函数有38个,下⾯我们仅介绍常⽤的函数。
2.1⼊⼝函数mexFunction
该函数是C MEX⽂件的⼊⼝函数,它的格式是固定的:
void mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[])
说明:MATLAB函数的调⽤⽅式⼀般为:[a,b,c,…]=被调⽤函数名称(d,e,f,…),nlhs保存了等号左端输出参数的个数,指针数组plhs具体保存了等号左端各参数的地址,注意在plhs各元素针向的mxArray内存未分配,需在接⼝过程中分配内存;prhs保存了等号右端输⼊参数的个数,指针数组prhs具体保存了等号右端各参数的地址,注意MATLAB在调⽤该MEX⽂件时,各输⼊参数已存在,所以在接⼝过程中不需要再为这些参数分配内存。
2.2出错信息发布函数mexErrMsgTxt,mexWarnMsgTxt
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论