標籤:mex檔案 dll matlab
Matlab是矩陣語言,如果運算可以用矩陣實現,其運算速度非常快。但若運算中涉及到大量迴圈,Matlab的速度令人難以忍受的。當必須使用for迴圈且找不到對應的矩陣運算來等效時,可以將耗時間長度的函數用C語言實現,並編譯成Mex檔案,Matlab便可以像調用內建函數一樣調用C編寫的函數。Mex檔案其實是一種動態連結程式庫,舊版本Matlab可以直接調用.dll,新版本要調用.mexw32或.mexw64檔案。
編譯過程需要C語言編譯器,在Matlab中鍵入mex –setup進行安裝與配置。
MEX檔案的原始碼組成:
(1)功能子程式。該過程包含了Mex檔案實現計算功能的代碼,是標準的C語言子程式。
(2)入口子程式。該過程提供功能子程式與Matlab之間的介面,以mexFunction函數實現。注意,入口過程的名稱必須是mexFunction,並且包含四個參數,即
void mexFunction(int nlhs,mxArray*plhs[],int nrhs,const mxArray *prhs[]);
nrhs(left hand side): 輸入參數的個數;
prhs是一個輸入數組,其內容為指標,指向mxArray類型的資料(MATLAB中所有資料都是以矩陣的形式mxArray儲存的)。
nlhs, plhs含義類似。
具體地,若在Matlab中執行[a,b]=test(c,d,e) ,則nlhs=2, nrhs=3,prhs[0]指向c,prhs[1]指向d,prhs[2]指向e(可以理解為:prhs[0]=&c, prhs[1]=&d, prhs[2]=&e),注意prhs是const指標數組,故不能改變其指向內容;函數返回時將plhs[0],plhs[1]指向的內容賦給a,b(可以理解為a=*plhs[0], b=*plhs[1])。
例:建立add.c,源碼如下:
#include "mex.h" double add(double x, double y){ return x + y;} 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);}
將add.c拷貝至Matlab目前的目錄,執行mex add.c,產生add.mexw64,該檔案實現求和功能。此時便可在Matlab中調用該函數:
>> output = add(1.1, 2.2);
分析:
#include "mex.h"
Mex源檔案必須包含mex.h,該標頭檔提供了大量Matlab與C(或Fortran)語言的之間的介面函數,函數首碼有mex-和mx-兩種,帶mx-首碼的大多是對mxArray資料進行操作的函數,如mxIsDouble,mxCreateDoubleMatrix等;而帶mex-首碼的則大多是與Matlab環境進行互動的函數,如mexPrintf,mexErrMsgTxt等。具體可參考Apiref.pdf。
plhs[0] = mxCreateDoubleMatrix(1, 1,mxREAL);
建立一個1x1的double類型的矩陣,返回剛建立的mxArray的地址,賦給指標plhs[0];
a = mxGetPr(plhs[0]);
返回指標plhs[0]所指向矩陣的第一個實數的地址,並賦給a;
b = *(mxGetPr(prhs[0]));
擷取指標prhs[0]指向矩陣的第一個實數,並賦給b;
*a = add(b, c);
調用C程式add,計算b,c之和並賦給a指向的內容;
例:建立myhilb.c,源碼如下:
#include "mex.h"void myhilb(double *y,int n){ int i,j; for(i=0;i<n;i++) for(j=0;j<n;j++) *(y+j+i*n)=1/((double)i+(double)j+1);}void mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[]){ double x,*y; if (nrhs!=1) mexErrMsgTxt("One inputs required."); if (!mxIsDouble(prhs[0])||mxGetN(prhs[0])*mxGetM(prhs[0])!=1) mexErrMsgTxt("Input must be scalars."); x=mxGetScalar(prhs[0]); plhs[0]=mxCreateDoubleMatrix(x,x,mxREAL); y=mxGetPr(plhs[0]); myhilb(y,(int)x);}
將myhilb.c拷貝至Matlab目前的目錄,執行mex myhilb.c,產生myhilb.mexw64,該檔案實現了計算Hilbert矩陣的功能(Hilbert矩陣:H(i,j)=1/(i+j-1))。
此時便可在Matlab中調用該函數:
>> output = myhilb (6);
分析:
mexFunction中進行了參數檢查,函數mexErrMsgTxt顯示出錯資訊後即退回到MATLAB。
mxGetScalar:擷取輸入矩陣第一個元素的實數部分;mxGetM:擷取矩陣的行數。
為了測試一下Mex檔案與m檔案的速度差異,編寫m檔案並運行之:
ticm=10000;a=zeros(m,m);for i=1:m for j=1:m a(i,j)=1/(i+j); endendtoc
結果:Elapsed time is3.620924 seconds.
接著運行Mex檔案
ticoutput = myhl(10000);toc
結果:Elapsed timeis 0.730596 seconds.
可以看出Mex檔案與M檔案速度差異很大。
VS2010產生Mex檔案(本人64位作業系統)
上述利用Matlab編譯產生Mex檔案,同樣也可以使用VS2010產生Mex檔案,只不過需要對VS環境進行配置,過程如下:
1、 建立一個win32 控制台的dll 空項目”myhilb”;
2、 建立源檔案myhilb.c,將上述myhilb.c內容拷進即可;
3、 添加.def檔案,內容為:
LIBRARY
EXPORTSmexFunction
4、 設定項目屬性, 開啟項目屬性配置頁:
(1)C/C++—>常規—>附加元件封裝含目錄,輸入matlab下安裝目錄下\extern\include
本人輸入E:\Matlab2010\Install\extern\include
(2)連結器->常規—>附加庫目錄,輸入matlab下安裝目錄下\extern\lib\win64\microsoft
本人輸入E:\Matlab2010\Install\extern\lib\win64\microsoft
(3)連接器 ->輸入->附加依賴項,輸入
libmx.lib
libeng.lib
libmat.lib
libmex.lib
(4)連結器->常規—>輸出檔案,輸入$(OutDir)$(TargetName).mexw64(若此處不更改,可在產生dll檔案後將尾碼名改為mexw64即可,這也驗證了Mex實際上就是DLL,只是尾碼名不同罷了)
(5)連結器->進階—>目標電腦,設為MachineX64(32位系統不用更改)
設定好點擊應用,執行了(5)的64位系統還需要在執行:
產生—>組態管理員—>活動解決平台,改為x64
5、按F7編譯工程,會在Debug下產生.mexw64檔案,如:
VS中單步調試Mex檔案
在Matlab環境下使用 mex –g myhilb.c命令進行調試,但無法加斷點進行單步調試,故需轉到VS環境下調試。
不管是利用VS還是利用Matlab產生Mex檔案,只要有c源檔案和Mex檔案就可以利用VS對Mex來源程式加斷點進行單步調試(我們用上面myhilb.c和myhilb.mexw64做測試)。
1、將Matlab目前的目錄改為Mex檔案(C檔案)所在目錄;
2、在VS2010中開啟C檔案,調試—>附加到進程,附加MATLAB.exe;
3、VS中在C源碼中添加斷點,在Matlab命令視窗調用Mex檔案提供的介面;
如Matlab執行:out=myhilb(6);
此時,VS2010中便可按F10進行單步調試:
要說明的是,在調試階段Matlab處於假死狀態,另外,Matlab調用了Mex檔案後需要執行clear all命令後才能刪除Mex檔案;
同樣地,若利用VS產生Mex檔案後直接將Matlab目前的目錄改至Debug目錄進行調試,則調試完必須執行clear all指令才能重新編譯工程。
參考:
http://blog.sina.com.cn/s/blog_468651400100coas.html
http://www.cppblog.com/xiaozhixd/articles/108490.html
http://www.linuxidc.com/Linux/2012-08/68148.htm
http://blog.sina.com.cn/s/blog_a7e72e940101cti9.html
http://blog.csdn.net/raodotcong/article/details/6317273
Matlab調用C程式