- 浏览: 489819 次
- 性别:
- 来自: 深圳
文章分类
- 全部博客 (185)
- job (15)
- linux/windows/unix/bash/shell (31)
- JAVA/J2EE/spring/hibernate/struts (30)
- VC/C++ (48)
- mysql/postgresql (6)
- php/jsp/asp/pear (1)
- FMS/flex/openlaszlo/red5/openmeetings (34)
- apache/tomcat/ftp/svn (6)
- xen/vm/Hadoop/cloudcompute (6)
- visual studio/eclipse/zendstudi/ant (8)
- others (1)
- windows异常处理 __try __except (1)
- (1)
- matlab (4)
- android (0)
最新评论
-
hongzhounlfd:
很透彻,很详细
依赖注入和控制反转 -
jefferyqjy:
谢谢~言简意赅~很明了!
依赖注入和控制反转 -
elderbrother:
太好了,谢谢
依赖注入和控制反转 -
east_zyd_zhao:
终于搞明白了
依赖注入和控制反转 -
Dremeng:
完美,一看就懂理解透彻
依赖注入和控制反转
Matlab以MEX方式调用C源代码
如果我有一个用C语言写的函数,实现了一个功能,如一个简单的函数:
double add(double x, double y)
{
return x + y;
}
现在我想要在Matlab中使用它,比如输入:
>> a = add(1.1, 2.2)
3.3000
要得出以上的结果,那应该怎样做呢?
解决方法之一是要通过使用MEX文件,MEX文件使得调用C函数和调用Matlab的内置函数一样方便。MEX文件是由原C代码加上MEX文件专用的接口函数后编译而成的。可以这样理解,MEX文件实现了一种接口,它把在Matlab中调用函数时输入的自变量通过特定的接口调入了C函数,得出的结果再通过该接口调回Matlab。该特定接口的操作,包含在mexFunction这个函数中,由使用者具体设定。
所以现在我们要写一个包含add和mexFunction的C文件,Matlab调用函数,把函数中的自变量(如上例中的1.1和2.2)传给 mexFunction的一个参数,mexFunction把该值传给add,把得出的结果传回给mexFunction的另一个参数,Matlab通过该参数来给出在Matlab语句中调用函数时的输出值(如上例中的a)。
值得注意的是,mex文件是与平台有关的,以我的理解,mex文件就是另类的动态链接库。在matlab6.5中使用mex -v 选项,你可以看到最后mex阶段有类似如下的信息:
--> "del _lib94902.obj"
--> "del "test.exp""
--> "del "test.lib""
也就是说,虽然在matlab6.5生成的是dll文件,但是中间确实有过lib文件生成。
比如该C文件已写好,名为add.c。那么在Matlab中,输入:
>> mex add.c
就能把add.c编译为MEX文件(编译器的设置使用指令mex -setup),在Windows中,MEX文件类型为mexw32,即现在我们得出add.mexw32文件。现在,我们就可以像调用M函数那样调用 MEX文件,如上面说到的例子。所以,通过MEX文件,使用C函数就和使用M函数是一样的了。
我们现在来说mexFunction怎样写。
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,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);
}
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便是已计算好的结果了。
上面说的一大堆指向这指向那,什么mxArray,初学者肯定都会被弄到头晕眼花了。很抱歉,要搞清楚这些乱糟糟的关系,只有多看多练。
实际上mexFunction是没有这么简单的,我们要对用户的输入自变量的个数和类型进行测试,以确保输入正确。如在add函数的例子中,用户输入char array便是一种错误了。
从上面的讲述中我们总结出,MEX文件实现了一种接口,把C语言中的计算结果适当地返回给Matlab罢了。当我们已经有用C编写的大型程序时,大可不必在 Matlab里重写,只写个接口,做成MEX文件就成了。另外,在Matlab程序中的部份计算瓶颈(如循环),可通过MEX文件用C语言实现,以提高计算速度。
以上是对mex文件的初步认识,下面详细介绍如何用c语言编写mex文件:
1 为什么要用C语言编写MEX文件
MATLAB是矩阵语言,是为向量和矩阵操作设计的,一般来说,如果运算可以用向量或矩阵实现,其运算速度是非常快的。但若运算中涉及到大量的循环处理,MATLAB的速度的令人难以忍受的。解决方法之一为,当必须使用for循环时,把它写为MEX文件,这样不必在每次运行循环中的语句时MATLAB都对它们进行解释。
2 编译器的安装与配置
要使用MATLAB编译器,用户计算机上应用事先安装与MATLAB适配的以下任何一种ANSI C/C++编译器:
5.0、6.0版的MicroSoft Visual C++(MSVC)
5.0、5.2、5.3、5.4、5.5版的Borland C++
LCC(由MATLAB自带,只能用来产生MEX文件)
下面是安装与配置MATLAB编译器应用程序MEX的设置的步骤:
(1)在MATLAB命令窗口中运行mex –setup,出现下列提示:
Please choose your compiler for building external interface (MEX) files:
Would you like mex to locate installed compilers [y]/n?
(2)选择y,MATLAB将自动搜索计算机上已安装的外部编译器的类型、版本及所在路径,并列出来让用户选择:
Select a compiler:
[1] Borland C++Builder version 6.0 in C:\Program Files\Borland
[2] Digital Visual Fortran version 6.0 in C:\Program Files\Microsoft Visual Studio
[3] Lcc C version 2.4 in D:\MATLAB6P5P1\sys\lcc
[4] Microsoft Visual C/C++ version 6.0 in C:\Program Files\Microsoft Visual Studio
[0] None
Compiler:
(3)选择其中一种(在这里选择了3),MATLAB让用户进行确认:
Please verify your choices:
Compiler: Lcc C 2.4
Location: D:\MATLAB6P5P1\sys\lcc
Are these correct?([y]/n):
(4)选择y,结束MATLAB编译器的配置。
3 一个简单的MEX文件例子
【例1】用m文件建立一个1000×1000的Hilbert矩阵。
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"
//计算过程
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,即可编译成功。进入该文件夹,会发现多了两个文件:Matlab_1.asv和Matlab_1.dll,其中Matlab_1.dll即是MEX文件。运行下面程序:
tic
a=Matlab_1(1000);
toc
elapsed_time =
0.0470
由上面看出,同样功能的MEX文件比m文件快得多。
4 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-函数。
5 常用的mex-函数和mx-函数
在MATLAB6.5版本中,提供的mx-函数有106个,mex-函数有38个,下面我们仅介绍常用的函数。
5.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文件时,各输入参数已存在,所以在接口过程中不需要再为这些参数分配内存。
5.2出错信息发布函数mexErrMsgTxt,mexWarnMsgTxt
两函数的具体格式如下:
#include "mex.h"
void mexErrMsgTxt(const char *error_msg);
void mexWarnMsgTxt(const char *warning_msg);
其中error_msg包含了要显示错误信息,warning_msg包含要显示的警告信息。两函数的区别在于mexErrMsgTxt显示出错信息后即返回到MATLAB,而mexWarnMsgTxt显示警告信息后继续执行。
5.3 mexCallMATLAB和mexString
两函数具体格式如下:
#include "mex.h"
int mexCallMATLAB(int nlhs, mxArray *plhs[],
int nrhs, mxArray *prhs[], const char *command_name);
int mexString(const char *command);
mexCallMATLAB前四个参数的含义与mexFunction的参数相同,command_name可以MATLAB内建函数名、用户自定义函数、M文件或MEX文件名构成的字符串,也可以MATLAB合法的运算符。
mexString用来操作MATLAB空间已存在的变量,它不返回任何参数。
mexCallMATLAB与mexString差异较大,请看下面的例子。
【例2】试用MEX文件求5阶完全图邻接矩阵 的特征值及对应的特征向量。
5阶完全图的邻接矩阵为:(这里找不到图片了,抱歉。不过不会影响您对本文的理解。)
下面是求该矩阵的MEX文件。
[Matlab_2.cpp]
#include "mex.h"
void mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[])
{
double x;
mxArray *y,*z,*w;
int n;
if (nrhs!=1)
mexErrMsgTxt("One inputs required.");
if (nlhs != 3)
mexErrMsgTxt("Three output required.");
if (!mxIsDouble(prhs[0])||mxGetN(prhs[0])*mxGetM(prhs[0])!=1)
mexErrMsgTxt("Input must be a scalar.");
x=mxGetScalar(prhs[0]);
plhs[0]=mxCreateDoubleMatrix(x,x,mxREAL);
plhs[1]=mxCreateDoubleMatrix(x,x,mxREAL);
plhs[2]=mxCreateDoubleMatrix(x,x,mxREAL);
n=mxGetM(plhs[0]);
y=plhs[0];
z=plhs[1];
w=plhs[2];
//利用mexCallMATLAB计算特征值
mexCallMATLAB(1,&plhs[1],1,prhs,"ones");
mexCallMATLAB(1,&plhs[2],1,prhs,"eye");
mexCallMATLAB(1,&plhs[0],2,&plhs[1],"-");
mexCallMATLAB(2,&plhs[1],1,&plhs[0],"eig");
//演示mexString的功能
mexString("y=y*2");
mexString("a=a*2");
}
在MATLAB命令窗口输入以下命令:
>> mex Matlab_2.cpp
>> clear
>> a=magic(5)
a =
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9
>> [y,z,w]=Matlab_2(5)
??? Undefined function or variable 'y'.
a =
34 48 2 16 30
46 10 14 28 32
8 12 26 40 44
20 24 38 42 6
22 36 50 4 18
y =
0 1 1 1 1
1 0 1 1 1
1 1 0 1 1
1 1 1 0 1
1 1 1 1 0
z =
0.8333 -0.1667 -0.1667 0.2236 0.4472
-0.1667 0.8333 -0.1667 0.2236 0.4472
-0.1667 -0.1667 0.8333 0.2236 0.4472
-0.5000 -0.5000 -0.5000 0.2236 0.4472
0 0 0 -0.8944 0.4472
w =
-1 0 0 0 0
0 -1 0 0 0
0 0 -1 0 0
0 0 0 -1 0
0 0 0 0 4
由上面可以看出,K5的特征值为–1和4,其中–1是四重根。MATLAB提供了mexGetVariable、mexPutVariable函数,以实现MEX空间与其它空间交换数据的任务,具体可以参看MATLAB帮助文档。
5.4建立二维双精度矩阵函数mxCreateDoubleMatrix
其格式具体如下:
#include "matrix.h"
mxArray *mxCreateDoubleMatrix(int m, int n, mxComplexity ComplexFlag);
其中m代表行数,n代表列数,ComplexFlag可取值mxREAL 或mxCOMPLEX。如果创建的矩阵需要虚部,选择mxCOMPLEX,否则选用mxREAL。
类似的函数有:
mxCreateCellArray
创建n维元胞mxArray
mxCreateCellMatrix
创建二维元胞mxArray
mxCreateCharArray
创建n维字符串mxArray
mxCreateCharMatrixFromStrings
创建二维字符串mxArray
mxCreateDoubleMatrix
创建二维双精度浮点mxArray
mxCreateDoubleScalar
创建指定值的二维精度浮点mxArray
mxCreateLogicalArray
创建n维逻辑mxArray,初值为false
mxCreateLogicalMatrix
创建二维逻辑mxArray,初值为false
mxCreateLogicalScalar
创建指定值的二维逻辑mxArray
mxCreateNumericArray
创建n维数值mxArray
mxCreateNumericMatrix
创建二维数值mxArray,初值为0
mxCreateScalarDouble
创建指定值的双精度mxArray
MxCreateSparse
创建二维稀疏mxArray
mxCreateSparseLogicalMatrix
创建二维稀疏逻辑mxArray
MxCreateString
创建指定字符串的1 n的串mxArray
mxCreateStructArray
创建n维架构mxArray
mxCreateStructMatrix
创建二维架构mxArray
5.5 获取行维和列维函数mxGetM、mxGetN
其格式如下:
#include "matrix.h"
int mxGetM(const mxArray *array_ptr);
int mxGetN(const mxArray *array_ptr);
与之相关的还有:
mxSetM:设置矩阵的行维
mxSetN:设置矩阵的列维
5.6 获取矩阵实部和虚部函数mxGetPr、mxGetPi
其格式如下:
#include "matrix.h"
double *mxGetPr(const mxArray *array_ptr);
double *mxGetPi(const mxArray *array_ptr);
与之相关的函数还有:
mxSetPr:设置矩阵的实部
mxSetPi:设置矩阵的虚部
【例3】实现字符串的倒序输出。
#include "mex.h"
void revord(char *input_buf,int buflen,char *output_buf)
{
int i;
//实现字符串倒序
for(i=0;i<buflen-1;i++)
*(output_buf+i)=*(input_buf+buflen-i-2);
}
void mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[])
{
//定义输入和输出参量的指针
char *input_buf,*output_buf;
int buflen,status;
//检查输入参数个数
if(nrhs!=1)
mexErrMsgTxt("One input required.");
else if(nlhs>1)
mexErrMsgTxt("Too many output arguments.");
//检查输入参数是否是一个字符串
if(mxIsChar(prhs[0])!=1)
mexErrMsgTxt("Input must be a string.");
//检查输入参数是否是一个行变量
if(mxGetM(prhs[0])!=1)
mexErrMsgTxt("Input must a row vector.");
//得到输入字符串的长度
buflen=(mxGetM(prhs[0])*mxGetN(prhs[0]))+1;
//为输入和输出字符串分配内存
input_buf=mxCalloc(buflen,sizeof(char));
output_buf=mxCalloc(buflen,sizeof(char));
//将输入参量的mxArray结构中的数值拷贝到C类型字符串指针
status=mxGetString(prhs[0],input_buf,buflen);
if(status!=0)
mexWarnMsgTxt("Not enough space. String is truncated.");
//调用C程序
revord(input_buf,buflen,output_buf);
plhs[0]=mxCreateString(output_buf);
}
这个程序中需要注意的地方是mxCalloc函数,它代替了标准C程序中的calloc函数用于动态分配内存,而mxCalloc函数采用的是MATLAB的内存管理机制,并将所有申请的内存初始化为0,因此凡是C代码需要使用calloc函数的地方,对应的Mex文件应该使用mxCalloc函数。同样,凡是C代码需要使用realloc函数的地方,对应的Mex文件应该使用mxRealloc函数。
在MATLAB命令窗口中对revord.cpp程序代码编译链接:
>> mex revord.cpp
在MATLAB命令窗口中对C-MEX文件revord.dll进行测试:
>> x='I am student.';
>> revord(x)
ans =
.tneduts ma I
如果我有一个用C语言写的函数,实现了一个功能,如一个简单的函数:
double add(double x, double y)
{
return x + y;
}
现在我想要在Matlab中使用它,比如输入:
>> a = add(1.1, 2.2)
3.3000
要得出以上的结果,那应该怎样做呢?
解决方法之一是要通过使用MEX文件,MEX文件使得调用C函数和调用Matlab的内置函数一样方便。MEX文件是由原C代码加上MEX文件专用的接口函数后编译而成的。可以这样理解,MEX文件实现了一种接口,它把在Matlab中调用函数时输入的自变量通过特定的接口调入了C函数,得出的结果再通过该接口调回Matlab。该特定接口的操作,包含在mexFunction这个函数中,由使用者具体设定。
所以现在我们要写一个包含add和mexFunction的C文件,Matlab调用函数,把函数中的自变量(如上例中的1.1和2.2)传给 mexFunction的一个参数,mexFunction把该值传给add,把得出的结果传回给mexFunction的另一个参数,Matlab通过该参数来给出在Matlab语句中调用函数时的输出值(如上例中的a)。
值得注意的是,mex文件是与平台有关的,以我的理解,mex文件就是另类的动态链接库。在matlab6.5中使用mex -v 选项,你可以看到最后mex阶段有类似如下的信息:
--> "del _lib94902.obj"
--> "del "test.exp""
--> "del "test.lib""
也就是说,虽然在matlab6.5生成的是dll文件,但是中间确实有过lib文件生成。
比如该C文件已写好,名为add.c。那么在Matlab中,输入:
>> mex add.c
就能把add.c编译为MEX文件(编译器的设置使用指令mex -setup),在Windows中,MEX文件类型为mexw32,即现在我们得出add.mexw32文件。现在,我们就可以像调用M函数那样调用 MEX文件,如上面说到的例子。所以,通过MEX文件,使用C函数就和使用M函数是一样的了。
我们现在来说mexFunction怎样写。
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,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);
}
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便是已计算好的结果了。
上面说的一大堆指向这指向那,什么mxArray,初学者肯定都会被弄到头晕眼花了。很抱歉,要搞清楚这些乱糟糟的关系,只有多看多练。
实际上mexFunction是没有这么简单的,我们要对用户的输入自变量的个数和类型进行测试,以确保输入正确。如在add函数的例子中,用户输入char array便是一种错误了。
从上面的讲述中我们总结出,MEX文件实现了一种接口,把C语言中的计算结果适当地返回给Matlab罢了。当我们已经有用C编写的大型程序时,大可不必在 Matlab里重写,只写个接口,做成MEX文件就成了。另外,在Matlab程序中的部份计算瓶颈(如循环),可通过MEX文件用C语言实现,以提高计算速度。
以上是对mex文件的初步认识,下面详细介绍如何用c语言编写mex文件:
1 为什么要用C语言编写MEX文件
MATLAB是矩阵语言,是为向量和矩阵操作设计的,一般来说,如果运算可以用向量或矩阵实现,其运算速度是非常快的。但若运算中涉及到大量的循环处理,MATLAB的速度的令人难以忍受的。解决方法之一为,当必须使用for循环时,把它写为MEX文件,这样不必在每次运行循环中的语句时MATLAB都对它们进行解释。
2 编译器的安装与配置
要使用MATLAB编译器,用户计算机上应用事先安装与MATLAB适配的以下任何一种ANSI C/C++编译器:
5.0、6.0版的MicroSoft Visual C++(MSVC)
5.0、5.2、5.3、5.4、5.5版的Borland C++
LCC(由MATLAB自带,只能用来产生MEX文件)
下面是安装与配置MATLAB编译器应用程序MEX的设置的步骤:
(1)在MATLAB命令窗口中运行mex –setup,出现下列提示:
Please choose your compiler for building external interface (MEX) files:
Would you like mex to locate installed compilers [y]/n?
(2)选择y,MATLAB将自动搜索计算机上已安装的外部编译器的类型、版本及所在路径,并列出来让用户选择:
Select a compiler:
[1] Borland C++Builder version 6.0 in C:\Program Files\Borland
[2] Digital Visual Fortran version 6.0 in C:\Program Files\Microsoft Visual Studio
[3] Lcc C version 2.4 in D:\MATLAB6P5P1\sys\lcc
[4] Microsoft Visual C/C++ version 6.0 in C:\Program Files\Microsoft Visual Studio
[0] None
Compiler:
(3)选择其中一种(在这里选择了3),MATLAB让用户进行确认:
Please verify your choices:
Compiler: Lcc C 2.4
Location: D:\MATLAB6P5P1\sys\lcc
Are these correct?([y]/n):
(4)选择y,结束MATLAB编译器的配置。
3 一个简单的MEX文件例子
【例1】用m文件建立一个1000×1000的Hilbert矩阵。
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"
//计算过程
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,即可编译成功。进入该文件夹,会发现多了两个文件:Matlab_1.asv和Matlab_1.dll,其中Matlab_1.dll即是MEX文件。运行下面程序:
tic
a=Matlab_1(1000);
toc
elapsed_time =
0.0470
由上面看出,同样功能的MEX文件比m文件快得多。
4 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-函数。
5 常用的mex-函数和mx-函数
在MATLAB6.5版本中,提供的mx-函数有106个,mex-函数有38个,下面我们仅介绍常用的函数。
5.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文件时,各输入参数已存在,所以在接口过程中不需要再为这些参数分配内存。
5.2出错信息发布函数mexErrMsgTxt,mexWarnMsgTxt
两函数的具体格式如下:
#include "mex.h"
void mexErrMsgTxt(const char *error_msg);
void mexWarnMsgTxt(const char *warning_msg);
其中error_msg包含了要显示错误信息,warning_msg包含要显示的警告信息。两函数的区别在于mexErrMsgTxt显示出错信息后即返回到MATLAB,而mexWarnMsgTxt显示警告信息后继续执行。
5.3 mexCallMATLAB和mexString
两函数具体格式如下:
#include "mex.h"
int mexCallMATLAB(int nlhs, mxArray *plhs[],
int nrhs, mxArray *prhs[], const char *command_name);
int mexString(const char *command);
mexCallMATLAB前四个参数的含义与mexFunction的参数相同,command_name可以MATLAB内建函数名、用户自定义函数、M文件或MEX文件名构成的字符串,也可以MATLAB合法的运算符。
mexString用来操作MATLAB空间已存在的变量,它不返回任何参数。
mexCallMATLAB与mexString差异较大,请看下面的例子。
【例2】试用MEX文件求5阶完全图邻接矩阵 的特征值及对应的特征向量。
5阶完全图的邻接矩阵为:(这里找不到图片了,抱歉。不过不会影响您对本文的理解。)
下面是求该矩阵的MEX文件。
[Matlab_2.cpp]
#include "mex.h"
void mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[])
{
double x;
mxArray *y,*z,*w;
int n;
if (nrhs!=1)
mexErrMsgTxt("One inputs required.");
if (nlhs != 3)
mexErrMsgTxt("Three output required.");
if (!mxIsDouble(prhs[0])||mxGetN(prhs[0])*mxGetM(prhs[0])!=1)
mexErrMsgTxt("Input must be a scalar.");
x=mxGetScalar(prhs[0]);
plhs[0]=mxCreateDoubleMatrix(x,x,mxREAL);
plhs[1]=mxCreateDoubleMatrix(x,x,mxREAL);
plhs[2]=mxCreateDoubleMatrix(x,x,mxREAL);
n=mxGetM(plhs[0]);
y=plhs[0];
z=plhs[1];
w=plhs[2];
//利用mexCallMATLAB计算特征值
mexCallMATLAB(1,&plhs[1],1,prhs,"ones");
mexCallMATLAB(1,&plhs[2],1,prhs,"eye");
mexCallMATLAB(1,&plhs[0],2,&plhs[1],"-");
mexCallMATLAB(2,&plhs[1],1,&plhs[0],"eig");
//演示mexString的功能
mexString("y=y*2");
mexString("a=a*2");
}
在MATLAB命令窗口输入以下命令:
>> mex Matlab_2.cpp
>> clear
>> a=magic(5)
a =
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9
>> [y,z,w]=Matlab_2(5)
??? Undefined function or variable 'y'.
a =
34 48 2 16 30
46 10 14 28 32
8 12 26 40 44
20 24 38 42 6
22 36 50 4 18
y =
0 1 1 1 1
1 0 1 1 1
1 1 0 1 1
1 1 1 0 1
1 1 1 1 0
z =
0.8333 -0.1667 -0.1667 0.2236 0.4472
-0.1667 0.8333 -0.1667 0.2236 0.4472
-0.1667 -0.1667 0.8333 0.2236 0.4472
-0.5000 -0.5000 -0.5000 0.2236 0.4472
0 0 0 -0.8944 0.4472
w =
-1 0 0 0 0
0 -1 0 0 0
0 0 -1 0 0
0 0 0 -1 0
0 0 0 0 4
由上面可以看出,K5的特征值为–1和4,其中–1是四重根。MATLAB提供了mexGetVariable、mexPutVariable函数,以实现MEX空间与其它空间交换数据的任务,具体可以参看MATLAB帮助文档。
5.4建立二维双精度矩阵函数mxCreateDoubleMatrix
其格式具体如下:
#include "matrix.h"
mxArray *mxCreateDoubleMatrix(int m, int n, mxComplexity ComplexFlag);
其中m代表行数,n代表列数,ComplexFlag可取值mxREAL 或mxCOMPLEX。如果创建的矩阵需要虚部,选择mxCOMPLEX,否则选用mxREAL。
类似的函数有:
mxCreateCellArray
创建n维元胞mxArray
mxCreateCellMatrix
创建二维元胞mxArray
mxCreateCharArray
创建n维字符串mxArray
mxCreateCharMatrixFromStrings
创建二维字符串mxArray
mxCreateDoubleMatrix
创建二维双精度浮点mxArray
mxCreateDoubleScalar
创建指定值的二维精度浮点mxArray
mxCreateLogicalArray
创建n维逻辑mxArray,初值为false
mxCreateLogicalMatrix
创建二维逻辑mxArray,初值为false
mxCreateLogicalScalar
创建指定值的二维逻辑mxArray
mxCreateNumericArray
创建n维数值mxArray
mxCreateNumericMatrix
创建二维数值mxArray,初值为0
mxCreateScalarDouble
创建指定值的双精度mxArray
MxCreateSparse
创建二维稀疏mxArray
mxCreateSparseLogicalMatrix
创建二维稀疏逻辑mxArray
MxCreateString
创建指定字符串的1 n的串mxArray
mxCreateStructArray
创建n维架构mxArray
mxCreateStructMatrix
创建二维架构mxArray
5.5 获取行维和列维函数mxGetM、mxGetN
其格式如下:
#include "matrix.h"
int mxGetM(const mxArray *array_ptr);
int mxGetN(const mxArray *array_ptr);
与之相关的还有:
mxSetM:设置矩阵的行维
mxSetN:设置矩阵的列维
5.6 获取矩阵实部和虚部函数mxGetPr、mxGetPi
其格式如下:
#include "matrix.h"
double *mxGetPr(const mxArray *array_ptr);
double *mxGetPi(const mxArray *array_ptr);
与之相关的函数还有:
mxSetPr:设置矩阵的实部
mxSetPi:设置矩阵的虚部
【例3】实现字符串的倒序输出。
#include "mex.h"
void revord(char *input_buf,int buflen,char *output_buf)
{
int i;
//实现字符串倒序
for(i=0;i<buflen-1;i++)
*(output_buf+i)=*(input_buf+buflen-i-2);
}
void mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[])
{
//定义输入和输出参量的指针
char *input_buf,*output_buf;
int buflen,status;
//检查输入参数个数
if(nrhs!=1)
mexErrMsgTxt("One input required.");
else if(nlhs>1)
mexErrMsgTxt("Too many output arguments.");
//检查输入参数是否是一个字符串
if(mxIsChar(prhs[0])!=1)
mexErrMsgTxt("Input must be a string.");
//检查输入参数是否是一个行变量
if(mxGetM(prhs[0])!=1)
mexErrMsgTxt("Input must a row vector.");
//得到输入字符串的长度
buflen=(mxGetM(prhs[0])*mxGetN(prhs[0]))+1;
//为输入和输出字符串分配内存
input_buf=mxCalloc(buflen,sizeof(char));
output_buf=mxCalloc(buflen,sizeof(char));
//将输入参量的mxArray结构中的数值拷贝到C类型字符串指针
status=mxGetString(prhs[0],input_buf,buflen);
if(status!=0)
mexWarnMsgTxt("Not enough space. String is truncated.");
//调用C程序
revord(input_buf,buflen,output_buf);
plhs[0]=mxCreateString(output_buf);
}
这个程序中需要注意的地方是mxCalloc函数,它代替了标准C程序中的calloc函数用于动态分配内存,而mxCalloc函数采用的是MATLAB的内存管理机制,并将所有申请的内存初始化为0,因此凡是C代码需要使用calloc函数的地方,对应的Mex文件应该使用mxCalloc函数。同样,凡是C代码需要使用realloc函数的地方,对应的Mex文件应该使用mxRealloc函数。
在MATLAB命令窗口中对revord.cpp程序代码编译链接:
>> mex revord.cpp
在MATLAB命令窗口中对C-MEX文件revord.dll进行测试:
>> x='I am student.';
>> revord(x)
ans =
.tneduts ma I
相关推荐
(精品)Matlab以MEX方式调用C源代码.pdf
MATLAB
MATLAB
MATLAB
MATLAB
。。。
蚁群算法作为一种需要多次迭代的算法, 在MATLAB下以.m脚本运行的效率是很慢的, MATLAB中for循环的低效率大家也体会到过吧.... 但是我不提供该MEX DLL的C++源代码, 因此你也就没法改算法了. 需要的话就邮件联系我好了.
使用 MATLAB MEX 文件从共享库调用异步函数的示例有关更多信息,请参阅 mexasync.c 源代码。
matlab分水岭算法源代码基于迭代H最小值的标记控制分水岭,用于细胞核分割 考虑到一组不同的h值,提出的算法可迭代地标识标记。 在每次迭代中,它使用特定的h值定义一组候选项,并从这些候选项中选择标记(只要它们...
sum函数源代码参考 Joseph K.Bradley,Aapo Kyrola,Danny Bickson和Carlos Guestrin(2011年)。 “用于L1正规化损耗最小化的平行坐标下降”。 国际机器学习会议(ICML 2011)。 安装 对于作为Matlab调用的mex代码...
matlab源代码如何运行 mexIPOPT 恩里科·贝托拉拉齐(Enrico Bertolazzi) 这是我为IPOPT编写的Peter Carbonetto MATLAB接口的重写,这是一个用于大规模非线性优化的软件包。 可以从以下网站下载IPOPT的源代码和文档...
H2Mex 是一个从头文件(.h 文件)自动生成接口文件(MEX 文件)的程序。 头文件格式是一种干净的 C 格式,它扩展了一些修饰符,允许 H2... 生成的源(MEX 文件源)无需任何修改即可编译以创建可从 MATLAB 调用的 DLL。
* "bobyqasub.m" MATLAB 文件由 mex 函数调用以评估目标函数,即 MATLAB 代码(.zip 文件)。 * “bobyqa_alg.cpp”文件包含用于创建 mex 函数的 C++ 源代码(在 .zip 文件中)。 * 包含 BOBYQA 算法的 dlib 源代码...
要从源代码在Matlab中安装SCS,请执行以下操作: git clone --recursive https://github.com/bodono/scs-matlab.git 然后在Matlab会话中 cd make_scs 这将产生两个mex文件,一个用于SCS的直接版本,另一个用于间接...
该实现既可以通过MEX调用在MATLAB内部使用,也可以直接使用其C / C ++接口作为独立工具使用。 侧面的图像是在matlab中从“ fulltest.m”创建的。 基本API kdtree_build:kd树构造O(n log ^ 2(n)) kdtree_delete...
哈夫曼函数源代码MATLAB 关于M4JPEG: M4JPEG项目旨在构建可在JPEG图像领域使用的Matlab编译的密写工具。 所提供的M4JPEG工具允许用户使用一种称为Mod4 [1]的自适应隐写方法在JPEG图像中隐藏私人文件。 现有文件夹:...
图像重建matlab源代码冲浪 冲浪是Matlab / Octave工具箱,用于在大脑皮质上选择基于表面的体素邻域,用于功能性磁共振成像(fMRI)数据的信息映射。 特征 基于皮层表面重建的体素选择。 支持Euclidian,Dijkstra和测...
形态学开学matlab代码用于体积形态学的球面结构单元的...下的源代码一起下载。 因此,您可能不必构建任何东西。 而只是: 将 .mexa64 和 .mexw64 放在 matlab 文件夹(或 MATLAB 可以找到它们的地方)。 将 (lib)pygorp