Matlab与C/C++混合编程有不少种方式,分别适用于不一样的状况。编程
Matlab有着很是详细的帮助文档,建议直接阅读其帮助文档,市面上不少Matlab书籍都是简单的翻译翻译帮助文档,例子都是照抄,还有不少错误和断章取义的地方,参考这样的书籍容易被带上弯路。数据结构
打开Matlab,按F1打开帮助,此部份内容在:编辑器
MATLAB->Advanced Software Development->MATALB API for Other Languages函数
简单来讲MEX-file是一种预编译的,用其余语言(C/C++,Fortran)编写的函数库,能够直接被Matlab调用。spa
正如前面提到的,这种方式适用于两种状况:scala
这两种状况用MEX-file的这种方案来解决都是很是合适的,由于这种调用方式很是方便,你须要注意地只是数据结构的转换。这种方式支持C/C++和Fortran,本文主要将C/C++。翻译
在Matlab命令窗口输入:debug
mex -setup
若是你的电脑已经安装了Matlab支持的编译器,这时候你应该会看到设置编译器的提示命令,跟着一步步下去就能够了。指针
注意:若是你电脑只安装了一个支持的编译器,这一步会自动用此编译器进行配置,若是有多个支持的编译器,Matlab会引导你选择要使用哪一个编译器。 若是你电脑没有安装合适的编译器,会获得一个错误,提示你安装合适的编译器,并给出一个支持编译器列表的连接。code
这一步能够用Matlab的编辑器也能够用其余你喜欢的编辑器,须要注意的是: 未来在Matlab中调用的函数名即为此处你建立的文件名,而不是文件内的函数名
MEX-file的内容
一个完整的MEX-file应该包括:
#include <mex.h>
MEX-file头文件mexFunction
入口函数(C/C++中的main函数)mexFunction
入口函数
void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]);
此函数是MEX-file的入口函数,形式比较固定,起着C/C++语言中main函数的做用,建议放在整个文件的最后。
mexFunction
函数中通常只作数据的转换和其余函数的调用,不作复杂的处理。
prhs
-函数右侧,输入参数plhs
-函数左侧,输出参数nrhs
-函数右侧,输入参数的个数nlhs
-函数左侧,输出参数的个数例如:在Matlab中用[a,b]=myMEX(c,d,e)
的形式调用的函数,则nrhs==3
表明有三个输入参数,nlhs==2
表明有两个输入参数,参数值分别储存在prhs
和plhs
中。 输入输出数据的校验
这一部分建议放在mexFunction
里面,校验输入输出参数的个数是否符合要求,校验输入参数的类型是否符合要求。
这里的输入参数是 只读 的,不要尝试更改,否则会引发错误。
建立一个可更改的输入参数的副本myData
并调用mxDuplicateArray
函数:
mxArray *myData = mxCreateStructMatrix(1,1,nfields,fnames); mxSetField(myData,0,"myFieldName",mxDuplicateArray(prhs[0]));
对于输入参数类型的校验能够用mxIsClass
中的函数来进行:
if(mxIsSparse(prhs[1])||mxIsComplex(prhs[1])||mxIsClass(prhs[1],"char")) { mexErrMsgTxt("input2 must be full matrix of real values."); }
完整的mxIsClass
函数列表见附录。
这一部分主要涉及如何将输入参数中的数据传出,而且用C/C++的数据结构来表示,以及如何构建输出参数,将运算结果传回Matlab。
因为Matlab中数据结构种类比较多,且比较复杂,这里并不会一一涉及,只介绍几种比较经常使用的数据类型,其余数据类型你们能够自行查阅Matlab帮助文档。
如下的示例代码都假设你须要传递的输入参数是第一个,若是为其余,只需修改prhs的角标便可
标量的传递
size_t mrows; //行数 size_t ncols; //列数 double scalar; //接收输入参数的变量 mrows = mxGetM(prhs[0]); //获取矩阵行数 ncols = mxGetN(prhs[0]); //获取矩阵列数 /*校验输入是不是一个标量*/ if( !mxIsDouble(prhs[0]) || mxIsComplex(prhs[0]) || !(mrows==1 && ncols==1) ) { mexErrMsgIdAndTxt( "MATLAB:timestwo:inputNotRealScalarDouble","Input must be a noncomplex scalar double."); } scalar = mxGetScalar(prhs[0]); //获取标量值
矩阵的传递
size_t mrows; //行数 size_t ncols; //列数 mxArray *inMat; //接收输入参数的指针 mrows = mxGetM(prhs[0]); //获取矩阵行数 ncols = mxGetN(prhs[0]); //获取矩阵列数 /*校验输入是不是一个3*4的double矩阵 矩阵维数的校验也能够去掉(相应的你的处理函数要有处理不一样大小矩阵的能力)*/ if( !mxIsDouble(prhs[0]) || mxIsComplex(prhs[0]) || !(mrows==3 && ncols==4) ) { mexErrMsgIdAndTxt( "MATLAB:timestwo:inputNotRealScalarDouble", "Input must be a noncomplex double matrix."); } /*获取输入矩阵的指针*/ inMat = mxGetPr(prhs[0]);
为输出变量分配内存并传递给mexFunction
的输出参数
mxArray *outMat; outMat = mxCreateDoubleMatrix((mwSize)mrows,(mwSize)ncols,mxREAL); plhs[0] = outMat;
这里须要注意的是Matlab中矩阵的储存是列优先的,而C语言中是行优先的,在调用矩阵元素时须要注意:
double result; /* 将iMat中的第 i行 j列的元素值赋给result */ result = inMat[j*mrows+i]
为输出变量分配内存并传递给mexFunction
的输出参数
mxArray *outMat; outMat = mxCreateDoubleMatrix((mwSize)mrows,(mwSize)ncols,mxREAL); plhs[0] = outMat;
字符串的传递
将输入参数转换为C-type
的string
string input_buf; input_buf = mxArrayToString(prhs[0]);
为输出字符串分配内存
string output_buf; output_buf=mxCalloc(buflen, sizeof(char));
将输出字符串传递给输出参数
plhs[0] = mxCreateString(output_buf);
最后释放内存
mxFree(input_buf);
Structure和Cell类型的传递
Structure
和Cell
类型的传递其实与其余类型类似,他们是mxArray
类型。
mxGetField
和mxGetCell
函数能够用来获取指向Structure
和Cell
类型内容的mxArray
类型的指针。
mxGetNumberOfFields
和mxGetNumberOfElements
能够用来获取Structure
的条目的个数和元素的个数。
mxGetData
函数能够用来获取mxArray
变量中包含的数据。
由于Matlab中Cell
的应用比Structure
频繁,而且这二者结构数据传递方式很相似,此处以Cell
进行讲解: 假设咱们的输入参数Cell
中第一个元素是一个1x3
的矩阵,第二个元素仍是一个Cell
,这个Cell
里面包含两个1x3
的矩阵,在Matlab中构建方法以下:
temp = []; temp{1} = [1:3]; temp{2} = [4:6]; Cell = []; Cell{1} = [1:3]; Cell{2} = temp;
如今咱们若是咱们想将Cell
传入MEX-file中进行处理,读出Cell
中第第一个元素[1:3]
和第二个元素temp
,这个元素仍是一个Cell
,这在Matlab中很常见,能够以下操做:
mxArray *mat; //指向第一个元素[1:3]的指针 mxArray *Cell; //指向第二个元素的指针,仍是一个Cell size_t nrows; //行数 size_t ncols; //列数 double *data; //数据 int i; //循环变量 int j; /* 获取输入Cell的维数 */ mrows = mxGetM(prhs[0]); ncols = mxGetN(prhs[0]); /* 输出Cell的维数,这里做为示例我并无保存Cell的维数,后面获取Cell中元素维数时仍是用的这两个变量 */ mxPrintf("rows:%d,cols:%d\n",mrows,ncols); /* 取出Cell中第一个元素,此处mat是一个指向矩阵的mxArray指针,data储存的是数据 */ mat = mxGetCell(prhs[0],0); data = (double*)mxGetData(mat); /* 打印矩阵内的元素 [1:3]*/ mrows = mxGetM(mat); ncols = mxGetN(mat); for (i=0;i<mrows;i++) { for (j=0;j<ncols;j++) { mxPrintf("%f ",data[j*M+i]); } mxPrintf("\n"); } /* 取出Cell中第二个元素 仍是一个Cell 再取出里面内容的方法与上述过程一致 继续调用mxGetCell */ Cell = mxGetCell(prhs[0],1);
关于在Mex-file中构建Cell
的方法,这里不详细讲了,由于我的以为这么作吃力不讨好,何不把数据分别传入Matlab再从新组织呢?若是你真的想要在MEX-file里面构建Cell
并传出,原理是建立一个相应大小的mxArray
,由于Cell
自己就是mxArrary
类型的,而后将这部份内存的地址传给plhs
。
MEX-file的编译和调用
将Matlab的当前目录切换到你MEX-file所在的目录,假设你的文件名为helloMEX.c
,在Matlab命令窗口输入
mex helloMEX.c
若是获得MEX completed successfully
.的提示即为编译成功,若是不成功,会显示错误的位置和缘由,对应修改便可。
编译成功后会获得后缀为.mexw64
的文件(后缀名与平台相关,此为win64下的后缀名,其余平台不一样),将此文件添加入Matlab的路径中,或者将当前目录切换到此文件所在目录,便可像普通的Matlab函数同样调用此文件。
mxIsClass
函数列表(更详细的介绍参见Matlab帮助文档)
mxIsDouble() //Determine whether mxArray represents data as double-precision, floating-point numbers mxIsSingle() //Determine whether array represents data as single-precision, floating-point numbers mxIsComplex() //Determine whether data is complex mxIsNumeric() //Determine whether array is numeric mxIsInt64() //Determine whether array represents data as signed 64-bit integers mxIsUint64() //Determine whether array represents data as unsigned 64-bit integers mxIsInt32() //Determine whether array represents data as signed 32-bit integers mxIsUint32() //Determine whether array represents data as unsigned 32-bit integers mxIsInt16() //Determine whether array represents data as signed 16-bit integers mxIsUint16() //Determine whether array represents data as unsigned 16-bit integers mxIsInt8() //Determine whether array represents data as signed 8-bit integers mxIsUint8() //Determine whether array represents data as unsigned 8-bit integers mxIsChar() //Determine whether input is string array mxIsLogical() //Determine whether array is of type mxLogical mxIsLogicalScalar() //Determine whether scalar array is of type mxLogical mxIsLogicalScalarTrue() //Determine whether scalar array of type mxLogical is true mxIsStruct() //Determine whether input is structure array mxIsCell() //Determine whether input is Cell array mxIsClass() //Determine whether array is member of specified class mxIsInf() //Determine whether input is infinite mxIsFinite() //Determine whether input is finite mxIsNaN() //Determine whether input is NaN (Not-a-Number) mxIsEmpty() //Determine whether array is empty mxIsSparse() //Determine whether input is sparse array mxIsFromGlobalWS() //Determine whether array was copied from MATLAB global workspace mxAssert() //Check assertion value for debugging purposes mxAssertS() //Check assertion value without printing assertion text