MATLAB以MEX方式调用C/C++源代码(怎样写mex函数)

时间:2022-09-06 15:10:03

部分转载地址:https://wenku.baidu.com/view/f56cfe83bceb19e8b8f6bac5.html

一、MEX文件相关介绍 
如果我有一个用C/C++语言写的函数,实现了一个功能,如一个简单的函数:

 double add(double x, double y)

 { 
return x + y; 

现在我想要在Matlab中使用它,比如输入:

 >> a = add(1.1, 2.2)     3.3000 
要得出以上的结果,那应该怎样做呢?

解决方法之一 :


要通过使用MEX文件,MEX文件使得调用C/C++函数和调用Matlab的内置函数一样方便。MEX文件是由原C/C++代码加上MEX文件专用的接口函数后编译而成的。可以这样理解,MEX文件实现了一种接口,它把在Matlab中调用函数时输入的自变量通过特定的接口调入了C/C++函数,得出的结果再通过该接口调回Matlab。该特定接口的操作,包含在mexFunction这个函数中,由使用者具体设定。 
所以现在我们要写一个包含add和mexFunction的C/C++文件,Matlab调用函数,把函数中的自变量(如上例中的1.1和2.2)传给 mexFunction的一个参数,mexFunction把该值传给add,把得出的结果传回给mexFunction的另一个参数,Matlab通过该参数来给出在Matlab语句中调用函数时的输出值(如上例中的a)。 
值得注意的是,mex文件是与平台有关的,以我的理解,mex文件就是另类的动态链接库。比如该C/C++文件已写好,名为add.cpp。那么在Matlab中,输入:

 >> mex add.cpp 
就能把add.cpp编译为MEX文件。(在这之前要使用mex –setup命令来选择并设置编译器),在Windows中,MEX文件类型为mexw32或者mexw64(分别对应32位和64位计算机),即现在我们得出add.mexw64文件。现在,我们就可以像调用M函数那样调用 MEX文件,如上面说到的例子。所以,通过MEX文件,使用C/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/C++语言中,Matlab的array使用mxArray类型来表示。所以就不难明白为什么plhs和prhs都是指向mxArray类型的指针数组。

完整的add.cpp如下:

 
#include "mex.h" // 使用MEX文件必须包含的头文件 // 执行具体工作的C/C++函数

#include "mex.h" // 使用MEX文件必须包含的头文件 // 执行具体工作的C/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的内容是什么意思呢?

(在书《MATLAB混合编程与工程应用》王素立,高洁,孙新德编著   有介绍   可去查阅)

nlhs:输出参数的个数

plhs[]:输出的参数

nrhs:输入参数的个数

prhs[]:输入的参数

我们知道,如果这样调用函数时:

 >> 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便是已计算好的结果了。

对于上面的add函数,可以和mexFunction函数写在一个文件中,也可以写在别一个文件中,当然mexFunction所在的文件必须包含对add函数的定义。还有可以将函数定义在一个动态库(DLL)中,具体实现接下来讲。 
实际上mexFunction是没有这么简单的,我们要对用户的输入自变量的个数和类型进行测试,以确保输入正确。如在add函数的例子中,用户输入char array便是一种错误了。 从上面的讲述中我们总结出,MEX文件实现了一种接口,把C语言中的计算结果适当地返回给Matlab罢了。

当我们已经有用C编写的大型程序时,大可不必在 Matlab里重写,只写个接口,做成MEX文件就成了。另外,在Matlab程序中的部份计算瓶颈(如循环),可通过MEX文件用C/C++语言实现,以提高计算速度。 
以上是对mex文件的初步认识,下面详细介绍如何用C/C++语言编写mex文件:

1 为什么要用C/C++语言编写MEX文件   
MATLAB是矩阵语言,是为向量和矩阵操作设计的,一般来说,如果运算可以用向量或矩阵实现,其运算速度是非常快的。但若运算中涉及到大量的循环处理,MATLAB的速度的令人难以忍受的。解决方法之一为,当必须使用for循环时,把它写为MEX文件,这样不必在每次运行循环中的语句时MATLAB都对它们进行解释。

2 编译器的安装与配置 
  要使用MATLAB编译器,用户计算机上应用事先安装与MATLAB适配的以下任何一种ANSI C/C++编译器: 
5.0、6.0版的MicroSoft Visual C++(MSVC) VS2005、VS2008、VS2010等 
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] Lcc-win32 C 2.4.1 in D:\MATLAB\R2010b\sys\lcc  
[2] Microsoft Visual C++ 2010 in E:\Program Files\Microsoft Visual Studio 10.0  [3] Microsoft Visual C++ 6.0 in E:\Microsoft Visual Studio\MSDev98    [0] None   
Compiler:  
(3)选择其中一种(在这里选择了2),MATLAB让用户进行确认: Please verify your choices:    
Compiler: Microsoft Visual C++ 2010   
Location: E:\Program Files\Microsoft Visual Studio 10.0    
Are these correct [y]/n?  
(4)选择y,结束MATLAB编译器的配置。 

基本函数:

建立二维双精度矩阵函数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 
  
获取行维和列维函数mxGetM、mxGetN 其格式如下:

 #include "matrix.h" 
int mxGetM(const mxArray *array_ptr); 

int mxGetN(const mxArray *array_ptr); 与之相关的还有: 

mxSetM:设置矩阵的行维

 mxSetN:设置矩阵的列维 
获取矩阵实部和虚部函数mxGetPr、mxGetPi 其格式如下:

 #include "matrix.h" 
double *mxGetPr(const mxArray *array_ptr); 

double *mxGetPi(const mxArray *array_ptr); 与之相关的函数还有: 

mxSetPr:设置矩阵的实部 

mxSetPi:设置矩阵的虚部