Matlab C混合编程


由于看的代码里面以及一些工程需要涉及一些Matlab 混合编程,一直想看一下,首先一个就是使用C编写代码,编译之后由Matlab调用,这需要用到Mex函数,mex程序就是根据一定的接口规范(mtlab提出的)编写的一个dll,Mex文件既可以用c,也可以用fortran来编。本文介绍的是用C编写的。

这样做,若是代码中有循环的话,使用matlab的话需要循环解释多次,而使用C语言编译成dll之后,首先可以将循环体放入二进制程序中,利用matlab加快运算,而不是循环解释执行matlab代码。还有就是使用C可以加快代码的开发效率。

设置编译器路径
在Matlab 命令窗口键入    mex -setup,下面只要根据提示一步步设置就可以了。
为了测试你的路径设置正确与否,把下面的程序存为hello.c。
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
   mexPrintf("hello,world!\n");
}

假设你把hello.c放在了C:\TEST\下,在Matlab里用CD C:\TEST\ 将当前目录改为C:\TEST\(注意,仅将C:\TEST\加入搜索路径是没有用的)。现在敲:
mex hello.c
   如果一切顺利,编译应该在出现编译器提示信息后正常退出。如果你已将C:\TEST\加入了搜索路径,现在键入hello,程序会在屏幕上打出一行: hello,world!
看看C\TEST\目录下,你会发现多了一个文件:HELLO.DLL。说明Mex函数已经完成,编译成功
 
接口函数规范mexFunction介绍
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
nlhs:输出参数数目 
plhs:指向输出参数的指针 
nrhs:输入参数数目 
例如,使用
[a,b]=test(c,d,e)
调用mex函数test时,传给test的这三个参数分别是 prhs[0]=c ,prhs[1]=d ,prhs[2]=e 
当函数返回时,将会把你放在plhs[0],plhs[1]里的地址赋给a和b,达到返回数据的目的。  
细心的你也许已经注意到,prhs[i]和plhs[i]都是指向类型mxArray类型数据的指针。 这个类型是在mex.h中定义的,事实上,在Matlab里大多数数据都是以这种类型存在。当然还有其他的数据类型,可以参考Apiguide.pdf里的介绍。
为了让大家能更直观地了解参数传递的过程,我们把hello.c改写一下,使它能根据输 入参数的变化给出不同的屏幕输出:
//hello.c 2.0 
#include "mex.h" 
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 
{
int i; 
i=mxGetScalar(prhs[0]); 
if(i==1) 
  mexPrintf("hello,world!\n"); 
else 
  mexPrintf("大家好!\n"); 
}


将这个程序编译通过后,执行hello(1),屏幕上会打出: 
          hello,world! 
而hello(0)将会得到: 
           大家好! 
现在,程序hello已经可以根据输入参数来给出相应的屏幕输出。在这个程序里,除了用到了屏幕输出函数mexPrintf(用法跟c里的printf函数几乎完全一样)外,还用到了一个函数:mxGetScalar,调用方式如下: 
i=mxGetScalar(prhs[0]); 
"Scalar"就是标量的意思。在Matlab里数据都是以数组的形式存在的,mxGetScalar的作用就是把通过prhs[0]传递进来的mxArray类型的指针指向的数据(标量)赋给C程序里的变量。这个变量本来应该是double类型的,通过强制类型转换赋给了整形变量i。既然有标量,显然还应该有矢量,否则矩阵就没法传了。看下面的程序: 
//hello.c 2.1 
#include "mex.h" 
void mexFunction(int nlhs, mxArray *plhs[], 
int nrhs, const mxArray *prhs[]) 
{ 
int *i; 
i=mxGetPr(prhs[0]); //prhs是一个指针数组(每一个是一个指针),所以返回一个指针
if(i[0]==1) 
  mexPrintf("hello,world!\n"); 
else 
  mexPrintf("大家好!\n"); 
}  


这样,就通过mxGetPr函数从指向mxArray类型数据的prhs[0]获得了指向double类型的指针。

但是,还有个问题,如果输入的不是单个的数据,而是向量或矩阵,那该怎么处理呢 ?通过mxGetPr只能得到指向这个矩阵的指针,如果我们不知道这个矩阵的确切大小,就 没法对它进行计算。 

为了解决这个问题,Matlab提供了两个函数mxGetM和mxGetN来获得传进来参数的行数 和列数。下面例程的功能很简单,就是获得输入的矩阵,把它在屏幕上显示出来: 
//show.c 1.0 
#include "mex.h" 
#include "mex.h" 
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 
{ 
double *data; 
int M,N; 
int i,j; 
data=mxGetPr(prhs[0]); //获得指向矩阵的指针 
M=mxGetM(prhs[0]); //获得矩阵的行数 
N=mxGetN(prhs[0]); //获得矩阵的列数 
for(i=0;i<M;i++) 
{   for(j=0;j<N;j++) 
     mexPrintf("%4.3f  ",data[j*M+i]); 
     mexPrintf("\n"); 
  }
} 


编译完成后,用下面的命令测试一下: 
  a=1:10; 
  b=[a;a+1]; 
  show(a) 
  show(b) 


还有就是若是数据不是二维的,可以通过下面的函数获得数据的维度个数(向量:1,矩阵:2,...)以及维度数组。

  1.     // 获取维度个数  
  2.     numOfDim = mxGetNumberOfDimensions(pArray);  
  3.     // 获取维度数组  
  4.     Dims = mxGetDimensions(pArray);

需要注意的是,在Matlab里,矩阵第一行是从1开始的,而在C语言中,第一行的序数为零,Matlab里的矩阵元素b(i,j)在传递到C中的一维数组data后对应于data[j*M+i] 。 输入数据是在函数调用之前已经在Matlab里申请了内存的,由于mex函数与Matlab共用同一个地址空间,因而在prhs[]里传递指针就可以达到参数传递的目的。但是,输出参数却需要在mex函数内申请到内存空间,才能将指针放在plhs[]中传递出去。由于返回指针类型必须是mxArray,所以Matlab专门提供了一个函数:mxCreateDoubleMatrix来实现内存的申请,函数原型如下: 
   mxArray *mxCreateDoubleMatrix(int m, int n, mxComplexity ComplexFlag) 
   m:待申请矩阵的行数 
   n:待申请矩阵的列数 
为矩阵申请内存后,得到的是mxArray类型的指针,就可以放在plhs[]里传递回去了。但是对这个新矩阵的处理,却要在函数内完成,这时就需要用到前面介绍的mxGetPr。使用 mxGetPr获得指向这个矩阵中数据区的指针(double类型)后,就可以对这个矩阵进行各种操作和运算了。下面的程序是在上面的show.c的基础上稍作改变得到的,功能是将输出处理后的元素:
//reverse.c 1.0 
#include "mex.h" 
void mexFunction(int nlhs, mxArray *plhs[], 
    int nrhs, const mxArray *prhs[]) 
{ 
double *inData; 
double *outData; 
int M,N; 
int i,j; 
inData=mxGetPr(prhs[0]); 
M=mxGetM(prhs[0]); 
N=mxGetN(prhs[0]); 
plhs[0]=mxCreateDoubleMatrix(M,N,mxREAL); 
outData=mxGetPr(plhs[0]); 
for(i=0;i<M;i++) 
  for(j=0;j<N;j++) 
   outData[j*M+i]=inData[(N-1-j)*M+i]; 
} 


当然,Matlab里使用到的并不是只有double类型这一种矩阵,还有字符串类型、稀疏矩阵、结构类型矩阵等等,并提供了相应的处理函数。本文用到编制mex程序中最经常遇到的一些函数,其余的详细情况清参考Apiref.pdf。 
另外,若是不是输出元素,申请内存之后要记得释放:
mwSize *subScript; 
subScript = (mwSize *)mxCalloc( numOfDim,  sizeof ( mwSize ) ); 
mxFree( subScript ); 
通过前面两部分的介绍,大家对参数的输入和输出方法应该有了基本的了解。具备了这些知识,就能够满足一般的编程需要了。但这些程序还有些小的缺陷,以前面介绍的re由于前面的例程中没有对输入、输出参数的数目及类型进行检查,导致程序的容错性很差,以下程序则容错性较好
#include "mex.h" 
void mexFunction(int nlhs, mxArray *plhs[],  int nrhs, const mxArray *prhs[]) 
{ 
double *inData; 
double *outData; 
int M,N; 
//异常处理 
//异常处理 
if(nrhs!=1) 
    mexErrMsgTxt("USAGE: b=reverse(a)\n"); 
  if(!mxIsDouble(prhs[0])) 
   mexErrMsgTxt("the Input Matrix must be double!\n"); 
   inData=mxGetPr(prhs[0]); 
   M=mxGetM(prhs[0]); 
   N=mxGetN(prhs[0]); 
   plhs[0]=mxCreateDoubleMatrix(M,N,mxREAL); 
   outData=mxGetPr(plhs[0]); 
   for(i=0;i<M;i++) 
     for(j=0;j<N;j++) 
     outData[j*M+i]=inData[(N-1-j)*M+i]; 
  } 


在上面的异常处理中,使用了两个新的函数:mexErrMsgTxt和mxIsDouble。MexErrMsgTxt在给出出错提示的同时退出当前程序的运行。MxIsDouble则用于判断mxArray中的数据是否double类型。当然Matlab还提供了许多用于判断其他数据类型的函数,这里不加详述。 
需要说明的是,Matlab提供的API中,函数前缀有mex-和mx-两种。带mx-前缀的大多是对mxArray数据进行操作的函数,如mxIsDouble,mxCreateDoubleMatrix等等。而带mx前缀的则大多是与Matlab环境进行交互的函数,如mexPrintf,mxErrMsgTxt等等。了解了这一点,对在Apiref.pdf中查找所需的函数很有帮助。
另外,需要注意的是,当代码的后缀名为.c的时候,需要一次性把变量声明完,且放在代码的最前面,后缀为.cpp不会出现这个问题。

常用的Mex函数一览表

MX Matrix Library

mwIndex (C and Fortran)

Type for index values

mwPointer (Fortran)

Pointer type for platform

mwSignedIndex (C and Fortran)

Signed integer type for size values

mwSize (C and Fortran)

Type for size values

mxAddField (C and Fortran)

Field to structure array

mxArray (C and Fortran)

Type for MATLAB array

mxArrayToString (C)

Convert array to string

mxAssert (C)

Check assertion value for debugging purposes

mxAssertS (C)

Check assertion value without printing assertion text

mxCalcSingleSubscript (C and Fortran)

Offset from first element to desired element

mxCalloc (C and Fortran)

Allocate dynamic memory for array using MATLAB memory manager

mxChar (C)

Type for string array

mxClassID (C)

Enumerated value identifying class of array

mxClassIDFromClassName (Fortran)

Identifier corresponding to class

mxComplexity (C)

Flag specifying whether array has imaginary components

mxCopyCharacterToPtr (Fortran)

CHARACTER values from Fortran array to pointer array

mxCopyComplex16ToPtr (Fortran)

COMPLEX*16 values from Fortran array to pointer array

mxCopyComplex8ToPtr (Fortran)

COMPLEX*8 values from Fortran array to pointer array

mxCopyInteger1ToPtr (Fortran)

INTEGER*1 values from Fortran array to pointer array

mxCopyInteger2ToPtr (Fortran)

INTEGER*2 values from Fortran array to pointer array

mxCopyInteger4ToPtr (Fortran)

INTEGER*4 values from Fortran array to pointer array

mxCopyPtrToCharacter (Fortran)

CHARACTER values from pointer array to Fortran array

mxCopyPtrToComplex16 (Fortran)

COMPLEX*16 values from pointer array to Fortran array

mxCopyPtrToComplex8 (Fortran)

COMPLEX*8 values from pointer array to Fortran array

mxCopyPtrToInteger1 (Fortran)

INTEGER*1 values from pointer array to Fortran array

mxCopyPtrToInteger2 (Fortran)

INTEGER*2 values from pointer array to Fortran array

mxCopyPtrToInteger4 (Fortran)

INTEGER*4 values from pointer array to Fortran array

mxCopyPtrToPtrArray (Fortran)

Pointer values from pointer array to Fortran array

mxCopyPtrToReal4 (Fortran)

REAL*4 values from pointer array to Fortran array

mxCopyPtrToReal8 (Fortran)

REAL*8 values from pointer array to Fortran array

mxCopyReal4ToPtr (Fortran)

REAL*4 values from Fortran array to pointer array

mxCopyReal8ToPtr (Fortran)

REAL*8 values from Fortran array to pointer array

mxCreateCellArray (C and Fortran)

Unpopulated N-D cell array

mxCreateCellMatrix (C and Fortran)

Unpopulated 2-D cell array

mxCreateCharArray (C and Fortran)

Unpopulated N-D string array

mxCreateCharMatrixFromStrings (C and Fortran)

Create populated 2-D string array

mxCreateDoubleMatrix (C and Fortran)

2-D, double-precision, floating-point array initialized to 0

mxCreateDoubleScalar (C and Fortran)

Scalar, double-precision array initialized to specified value

mxCreateLogicalArray (C)

N-D logical array initialized to false

mxCreateLogicalMatrix (C)

2-D, logical array initialized to false

mxCreateLogicalScalar (C)

Scalar, logical array

mxCreateNumericArray (C and Fortran)

Unpopulated N-D numeric array

mxCreateNumericMatrix (C and Fortran)

Numeric matrix initialized to 0

mxCreateSparse (C and Fortran)

2-D unpopulated sparse array

mxCreateSparseLogicalMatrix (C)

Unpopulated 2-D, sparse, logical array

mxCreateString (C and Fortran)

Create 1-by-N array initialized to specified string

mxCreateStructArray (C and Fortran)

Unpopulated N-D structure array

mxCreateStructMatrix (C and Fortran)

Unpopulated 2-D structure array

mxDestroyArray (C and Fortran)

Free dynamic memory allocated by MXCREATE* functions

mxDuplicateArray (C and Fortran)

Make deep copy of array

mxFree (C and Fortran)

Free dynamic memory allocated by MXCALLOC, MXMALLOC, or MXREALLOC functions

mxGetCell (C and Fortran)

Contents of array cell

mxGetChars (C)

Pointer to character array data

mxGetClassID (C and Fortran)

Class of array

mxGetClassName (C and Fortran)

Class of array as string

mxGetData (C and Fortran)

Pointer to real data

mxGetDimensions (C and Fortran)

Pointer to dimensions array

mxGetElementSize (C and Fortran)

Number of bytes required to store each data element

mxGetEps (C and Fortran)

Value of EPS

mxGetField (C and Fortran)

Field value, given field name and index, into structure array

mxGetFieldByNumber (C and Fortran)

Field value, given field number and index, into structure array

mxGetFieldNameByNumber (C and Fortran)

Field name, given field number, in structure array

mxGetFieldNumber (C and Fortran)

Field number, given field name, in structure array

mxGetImagData (C and Fortran)

Pointer to imaginary data of array

mxGetInf (C and Fortran)

Value of infinity

mxGetIr (C and Fortran)

Sparse matrix IR array

mxGetJc (C and Fortran)

Sparse matrix JC array

mxGetLogicals (C)

Pointer to logical array data

mxGetM (C and Fortran)

Number of rows in array

mxGetN (C and Fortran)

Number of columns in array

mxGetNaN (C and Fortran)

Value of NaN (Not-a-Number)

mxGetNumberOfDimensions (C and Fortran)

Number of dimensions in array

mxGetNumberOfElements (C and Fortran)

Number of elements in array

mxGetNumberOfFields (C and Fortran)

Number of fields in structure array

mxGetNzmax (C and Fortran)

Number of elements in IR, PR, and PI arrays

mxGetPi (C and Fortran)

Imaginary data elements in array of type DOUBLE

mxGetPr (C and Fortran)

Real data elements in array of type DOUBLE

mxGetProperty (C and Fortran)

Value of public property of MATLAB object

mxGetScalar (C and Fortran)

Real component of first data element in array

mxGetString (C and Fortran)

String array to C-style string

mxIsCell (C and Fortran)

Determine whether input is cell array

mxIsChar (C and Fortran)

Determine whether input is string array

mxIsClass (C and Fortran)

Determine whether array is member of specified class

mxIsComplex (C and Fortran)

Determine whether data is complex

mxIsDouble (C and Fortran)

Determine whether mxArray represents data as double-precision, floating-point numbers

mxIsEmpty (C and Fortran)

Determine whether array is empty

mxIsFinite (C and Fortran)

Determine whether input is finite

mxIsFromGlobalWS (C and Fortran)

Determine whether array was copied from MATLAB global workspace

mxIsInf (C and Fortran)

Determine whether input is infinite

mxIsInt16 (C and Fortran)

Determine whether array represents data as signed 16-bit integers

mxIsInt32 (C and Fortran)

Determine whether array represents data as signed 32-bit integers

mxIsInt64 (C and Fortran)

Determine whether array represents data as signed 64-bit integers

mxIsInt8 (C and Fortran)

Determine whether array represents data as signed 8-bit integers

mxIsLogical (C and Fortran)

Determine whether array is of type mxLogical

mxIsLogicalScalar (C)

Determine whether scalar array is of type mxLogical

mxIsLogicalScalarTrue (C)

Determine whether scalar array of type mxLogical is true

mxIsNaN (C and Fortran)

Determine whether input is NaN (Not-a-Number)

mxIsNumeric (C and Fortran)

Determine whether array is numeric

mxIsSingle (C and Fortran)

Determine whether array represents data as single-precision, floating-point numbers

mxIsSparse (C and Fortran)

Determine whether input is sparse array

mxIsStruct (C and Fortran)

Determine whether input is structure array

mxIsUint16 (C and Fortran)

Determine whether array represents data as unsigned 16-bit integers

mxIsUint32 (C and Fortran)

Determine whether array represents data as unsigned 32-bit integers

mxIsUint64 (C and Fortran)

Determine whether array represents data as unsigned 64-bit integers

mxIsUint8 (C and Fortran)

Determine whether array represents data as unsigned 8-bit integers

mxLogical (C)

Type for logical array

mxMalloc (C and Fortran)

Allocate dynamic memory using MATLAB memory manager

mxRealloc (C and Fortran)

Reallocate dynamic memory using MATLAB memory manager

mxRemoveField (C and Fortran)

Remove field from structure array

mxSetCell (C and Fortran)

Value of one cell of array

mxSetClassName (C)

Convert structure array to MATLAB object array

mxSetData (C and Fortran)

Set pointer to data

mxSetDimensions (C and Fortran)

Modify number of dimensions and size of each dimension

mxSetField (C and Fortran)

Set structure array field, given structure field name and array index

mxSetFieldByNumber (C and Fortran)

Set structure array field, given field number and index

mxSetImagData (C and Fortran)

Imaginary data pointer for array

mxSetIr (C and Fortran)

IR array of sparse array

mxSetJc (C and Fortran)

JC array of sparse array

mxSetM (C and Fortran)

Number of rows in array

mxSetN (C and Fortran)

Set number of columns in array

mxSetNzmax (C and Fortran)

Set storage space for nonzero elements

mxSetPi (C and Fortran)

Set new imaginary data for array

mxSetPr (C and Fortran)

Set new real data for array

mxSetProperty (C and Fortran)

Set value of public property of MATLAB object

MEX Library

mexAtExit (C and Fortran)

Register function to call when MEX-function cleared or MATLAB software terminates

mexCallMATLAB (C and Fortran)

Call MATLAB function, user-defined function, or MEX-file

mexCallMATLABWithTrap (C and Fortran)

Call MATLAB function, user-defined function, or MEX-file and capture error information

mexErrMsgIdAndTxt (C and Fortran)

Display error message with identifier and return to MATLAB prompt

mexErrMsgTxt (C and Fortran)

Display error message and return to MATLAB prompt

mexEvalString (C and Fortran)

Execute MATLAB command in caller workspace

mexEvalStringWithTrap (C and Fortran)

Execute MATLAB command in caller workspace and capture error information

mexFunction (C and Fortran)

Entry point to C/C++ or Fortran MEX-file

mexFunctionName (C and Fortran)

Name of current MEX-function

mexGet (C)

Value of specified Handle Graphics property

mexGetVariable (C and Fortran)

Copy of variable from specified workspace

mexGetVariablePtr (C and Fortran)

Read-only pointer to variable from another workspace

mexIsGlobal (C and Fortran)

Determine whether variable has global scope

mexIsLocked (C and Fortran)

Determine whether MEX-file is locked

mexLock (C and Fortran)

Prevent clearing MEX-file from memory

mexMakeArrayPersistent (C and Fortran)

Make array persist after MEX-file completes

mexMakeMemoryPersistent (C and Fortran)

Make memory allocated by MATLAB software persist after MEX-function completes

mexPrintf (C and Fortran)

ANSI C PRINTF-style output routine

mexPutVariable (C and Fortran)

Array from MEX-function into specified workspace

mexSet (C)

Set value of specified Handle Graphics property

mexSetTrapFlag (C and Fortran)

Control response of MEXCALLMATLAB to errors

mexUnlock (C and Fortran)

Allow clearing MEX-file from memory

mexWarnMsgIdAndTxt (C and Fortran)

Warning message with identifier

mexWarnMsgTxt (C and Fortran)

Warning message



参考:

http://blog.sciencenet.cn/blog-620659-579885.html

http://blog.csdn.net/raodotcong/article/details/6295859

你可能感兴趣的:(Matlab C混合编程)