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