matlab 與c c 混合MEX的程式設計

2021-07-03 19:39:53 字數 4149 閱讀 3921

matlab中矩陣預算特別方便,但如果有無法避免的迴圈甚至多層巢狀的話,會非常影響程式的效率,因此通常會將這種需要大量迴圈的模組用c++編寫然後在matlab中呼叫。matlab中的的c++程式設計稱為mex程式設計(matlab executive),其中需要些乙個c++檔案,然後在matlab中用mex命令編譯它,然後就可以在matlab中像呼叫函式一樣呼叫c++**了。 

要使用mex編譯,首先要在matlab中配置c++編譯器,如果你的計算機中已經安裝了某個c++編譯器(例如vs或者gcc),在matlab命令列中直接輸入"mex -setup"就會有相應的提示,然後選擇下一步確定,編譯器就設定成功了。

接著就可以開始編寫mex的c++檔案了,下面舉個例子,新建乙個名為test.cpp的c++檔案,**內容如下:?

12

3

4

5

#include "mex.h"

voidmexfunction(intnlhs,mxarray* plhs,intnrhs,mxarray* rhs)

mex的原始檔一定要include標頭檔案"mex.h「,mex原始檔的入口函式為void mexfunction,這個函式有四個引數:nlhs(n left hand side) 等號左邊引數個數,plhs(pointer left hand side)等號左邊引數指標,另外兩個引數是等號右邊的個數和指標。

因為mex編譯完成之後在matlab中是當函式用的,函式就有輸入引數和返回引數,輸入引數就是等號右邊的引數,輸出引數就是等號左邊的引數,matlab中的函式允許有多個返回值,所以nlhs可以大於一。注意,指標plhs和prhs的型別為mxarray*,這是mex.h中定義的一種資料型別,是matlab裡矩陣在c++原始檔中的表示。

當編寫完上面的原始檔之後,在matlab裡執行命令"mex 檔名" 就可以編譯這個檔案,在這裡用 mex  test.cpp編譯它,編譯完成之後可以看到同目錄下生成了乙個同名的.mexw32(或者.mexw64,取決於你的編譯器是32bit還是64bit)檔案,然後在matlab命令中輸入test(),就可以看到列印出了"hello world "。這裡想再次強調,mex原始檔編譯完成之後在matlab裡當函式呼叫的。

1) mex程式設計中指標和索引:

matlab中預設的資料型別是double,用class()函式可以看到變數的資料型別:

分析下面一段**,matlab**如下:

mex test.cpp '-g'

;a = [1.1,2.1,3;4,5,6;7,8,9

]mex(a)

命令mex 用來編譯mex檔案,上面**中  mex  test.cpp 『-g』 編譯了test.cpp這個c++檔案,編譯完成之後會生成乙個「test.mexw64」的檔案,字尾名說明這是在win64下編譯完成的mex檔案,後面的'-g'是乙個附加引數,在這裡不用理解。編譯後的mex檔案可以當matlab函式使用。    

在matlab**檔案同目錄下的c檔案test.cpp**如下:

按 ctrl+c 複製**

按 ctrl+c 複製**

執行.m檔案,列印出結果如下:

在mex.cpp的**中,mexfunction有四個引數,nlhs( number left hand s):左邊引數個數,也就是matlab函式輸出值得個數,mxarray *plhs是乙個指標陣列,陣列中的每乙個元素都是乙個指標,指向輸出的矩陣;nrhs 是右邊引數個數,也就是輸入引數的個數,mxarray *prhs陣列中的每個指標指向輸入矩陣。mxgetpr()函式返回乙個double*型的指標,指向矩陣的第乙個元素,在matlab**中呼叫:mex(a),那也就是 prhs[0]是輸入矩陣a的位址,而 input = mxgetpr(prhs[0]) ,input指向了a第乙個元素1 。

那矩陣第一排第二列的值a(1,2)的位址是多少呢?是(input+1)嗎?在這裡我們執行上面的matlab**,

可以看出,輸出的*(input+1)是4,也就是說,c++中的matlab矩陣是按列進行索引的。這裡是乙個需要注意的地方,因為很多地方要對matlab輸入的矩陣進行遍歷得到矩陣的元素值,如果索引出錯,那就完全錯了。其實這裡的內在原因,是因為在matlab中矩陣是按列進行索引的,而c++中指標式按行往後加的。

有很多函式可以方便我們對矩陣進行索引,uint32 mxgetm(mxarray *)輸入乙個矩陣的指標,返回該矩陣的行數,uint32 mxgetn(mxarray *)返回列數,對行數和列數適當的計算,可以方便的訪問矩陣元素,例如,訪問a(i,j):   *(input+n*(j-1)+(i-1))  ,n為矩陣行數,這裡需要-1的原因是,matlab的行數列數從1開始計數,而c的陣列則從0開始索引。

2)mex程式設計中的資料型別與指標移位的重要關係,mxgetpr() 與 mxgetdata():

前面說過,matlab裡的預設資料型別是double,那麼,如果把mex函式的輸入矩陣的資料型別轉換一下,會出現什麼結果呢?

matlab **:

1

clc2 mex mex.cpp '-g'

;3 a = [1.1,2.1,3;4,5,6;7,8,9

];4 a=single(a)

5 mex(a)

c++**:

1 #include "

mex.h"2

void mexfunction(int nlhs, mxarray *plhs, int nrhs, const mxarray *prhs)

3

c++**並沒有變,matlab**也僅僅進行了乙個資料型別轉換,我們看看輸出結果:

可以看到這裡輸出的已經不是我們期望的數值了。在我除錯mex**的時候這個問題苦惱了我很久,因為mex不方便除錯,很多時候輸出的結果不是想要的,而且我的輸入矩陣都是上萬維的,很難除錯。這裡輸入矩陣a變成了single單精度型別,前面我們說過,mxgetpr()返回double型別的指標,當我們用double型別指標訪問乙個單精度(在c++)中我們稱之為浮點型float的資料的時候,當然會發成記憶體越界,用取值符號*去取值的時候超過了資料的記憶體塊,因此發生錯誤,如果我們修改c++**:

1 #include "

mex.h"2

void mexfunction(int nlhs, mxarray *plhs, int nrhs, const mxarray *prhs)

3

將input型別設定成float,並將mxgetpr()的返回型別強制轉換為float*就可以了。在這裡還有乙個函式mxgetdata()也可以返回輸入矩陣的頭位址,只不過mxgetdata()返回的是char*型別的指標,而mxgetpr()返回的是double*型別的指標,可以根據自己的需要選取函式,或者轉換指標型別。如果指標型別不對,極有可能造成記憶體訪問錯誤,導致matlab死掉。

3) nlhs 與 nrhs的作用 

mexfunction函式中,兩個指標引數分別指向輸入輸出的矩陣,而nrhs和nlhs分別記錄輸入輸出矩陣的個數,在一般的操作中,我們僅僅對輸入矩陣進行取值,運算,對輸出矩陣進行賦值,nrhs和nlhs不是很常用,但是也是極其重要的。例如,在上面的**中,如果我在matlab**中這樣呼叫mex:mex(),不輸入任何引數,matlab就會馬上死掉。因為在mex檔案的cpp**中,你用指標訪問了輸入矩陣的值,而在引數中你沒有給mex輸入任何引數,使得矩陣指標為野指標,導致記憶體錯誤。如果編碼中出現這種引數不對的情況,將導致matlab頻繁死掉,我的工作中資料特別多,準備資料需要幾十分鐘,這樣讓我非常痛苦。解決的方法就是利用nlhs和nrhs這兩個引數。在mexfunction中判斷nlhs的值來判斷輸入引數的個數,用nrhs判斷輸入引數的個數。如果輸入引數少於某個值或者不滿足你的要求可以讓mexfunction直接return,避免後續的程式導致記憶體錯誤。

matlab和C C 混合程式設計 Mex

最近的專案需要matlab和c的混合程式設計,經過一番努力終於完成了專案要解決的問題。現在就將mex的一些經驗總結一下,當然只是剛剛開始,以後隨著學習的深入繼續新增。首先講講寫mex的一些常規規定,然後我們會重點關注混合程式設計中最難解決資料的問題 結構到底如何轉換,並且後面會重點說一下自己的程式。...

Matlab與C 混合MEX程式設計

一 mexfunction 與c中的main函式一樣,mex程式中的開始函式為mexfunction.預設變數引數是 void mexfunction int nlhs,mxarray plhs,int nrhs,const mxarray prhs 其中nlhs指的是在呼叫函式時返回值的個數 pl...

Matlab中mex與C混合程式設計總結

使用mex和c可以加快演算法的執行速度,mex檔案包含乙個入口函式如下 void mexfunction int nlhs,mxarray plhs,int nrhs,const mxarray prhs 入口函式有四個引數 prhs為mxarray結構體型別的指標陣列,該陣列的元素按順序指向所有的...