程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> 關於C >> Matlab調用C程序

Matlab調用C程序

編輯:關於C

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

將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文件並運行之:

tic
m=10000;
a=zeros(m,m);
for i=1:m
     for j=1:m
         a(i,j)=1/(i+j);
     end
end
toc

結果:Elapsed time is3.620924 seconds.

接著運行Mex文件

 

 

tic
output = 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下安裝目錄下externinclude

本人輸入E:Matlab2010Installexterninclude

(2)鏈接器->常規—>附加庫目錄,輸入matlab下安裝目錄下externlibwin64microsoft

本人輸入E:Matlab2010Installexternlibwin64microsoft

(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指令才能重新編譯工程。

 

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved