1. 程式人生 > >關於matlab與C語言的混合程式設計

關於matlab與C語言的混合程式設計

摘要:本文著重描述了運用MATLAB命令將M檔案翻譯為C語言程式,並修改為可直接呼叫的C語言函式的方法,使用該方法所需要注意的方法侷限性和MATLAB版本差異的影響。運用該方法將能夠使C語言能直接使用MATLAB當中已經完成的數學計算功能,大大擴充了C語言的數學計算功能和開發效率。

  關鍵詞:MATLAB;M檔案;C語言介面 

  眾所周知,MATLAB是一個功能強大的數學軟體,擅長於用矩陣運算完成各種數學功能。但是其程式需要在MATLAB環境下解釋執行,效率不高。如果能將它強大的函式庫用於C語言,利用C來編譯執行,MATLAB將能發揮更大的作用。所以,MATLAB從5.0開始已經提供了與外部C/C++程式的應用程式介面,為利用C語言呼叫MATLAB的函式提供了可能。但是MATLAB的介面發展很快,到MATLAB 6.5已經提供了對VC 7.0的支援,同時對C的介面相對於5.X版本有了一定的改變。


  在MATLAB當中,我們利用M檔案來實現函式,每一個M檔案實現一個單獨的功能,這一點和C語言當中的函式是相互對應的。所以,如果我們能將MATLAB中的M檔案轉化為C語言下的一個單個函式,就能實現MATLAB中相應的功能。

  實現方法

  整個過程可分為三個主要部分,用MATLAB將M檔案翻譯為C語言檔案,從生成的C語言檔案提取出有用語句,編寫資料轉換程式實現引數格式轉換。整個過程最終將把M檔案翻譯成C語言當中的一個具有相同功能的函式,供其它的程式呼叫。

  本文用一個最簡單的M檔案來示例:

  檔名:messay.m

function c=messay()
a=3.4;
b=5.6;
c=sqrt(a)+sqrt(b); 


  該m檔案實現了計算 

  1、將M檔案編譯為C語言檔案

  為了將M檔案翻譯為C語言檔案,需要進行一定的設定,這裡假設編寫C語言的環境為VC6.0,在MATLAB命令提示符下輸入mex -setup和mbuild -setup命令,在相應選項中選擇Microsoft Visual C/C++即可。

  在MATLAB命令列中使用mcc命令將messay.m翻譯為C程式碼。

mcc -m messay.m 

  其中的引數-m代表mcc命令將把m檔案翻譯成C語言的程式碼。

  翻譯命令將在messay.m所在的資料夾下生成三個C語言檔案:messay.h,messay.c和messay_main.c。其中messay_main.c提供了main()函式;messay.h提供了整個程式的函式宣告;messay.c包含了MATLAB生成的功能函式。這三個檔案當中,messay.c中包含了我們所需要的數學函式。


  2、提取有用語句

  通過分析,發現由mcc生成的程式碼內部引數傳送方式由MATLAB連結庫規定,難以改動,因此需要提取有用的程式碼,並更改生成程式碼的引數傳遞方式。同時從生成程式碼的註釋中可以看出,真正蘊含M檔案功能實現的程式碼段都在Mmessay()函式當中(該函式名的預設構造方式為字首M加上M檔案的檔名),而其它的生成函式僅實現引數傳遞和標準化介面服務的功能。

  所以提取程式碼的具體方法是利用messay.c當中生成的static mxArray * Mmessay(int nargout_)函式,對該函式進行修改,而其他的生成函式都可以忽略不用。原生成的Mmessay()程式碼如下:

static mxArray * Mmessay(int nargout_) {
 mexLocalFunctionTable save_local_function_table = mclSetCurrentLocalFunctionTable(&_local_function_table_messay);
 mxArray * c = NULL;
 mxArray * b = NULL;
 mxArray * a = NULL;
 mlfAssign(&a, _mxarray0_);
 mlfAssign(&b, _mxarray1_);
 mlfAssign(&c, mclPlus(mlfSqrt(mclVv(a, "a")), mlfSqrt(mclVv(b, "b"))));
 mclValidateOutput(c, 1, nargout_, "c", "messay");
 mxDestroyArray(a);
 mxDestroyArray(b);
 mclSetCurrentLocalFunctionTable(save_local_function_table_);
 return c;


  在生成程式碼當中,mclSetCurrentLocalFunctionTable和mclSetCurrentLocalFunctionTable函式為兩個外部函式,將引數傳給外部,與其相關的部分都對C程式使用數學函式沒有影響。最終實際有用並執行運算的只有一句:

mlfAssign(&c, mclPlus(mlfSqrt(mclVv(a, "a")), mlfSqrt(mclVv(b, "b")))); 

  實際上,由MATLAB翻譯的C語句中,大部分的和實際計算有關的語句和自生成的函式都以mlf開頭,所以尋找有用語句的簡單方法就是直接尋找mlf為字首的程式碼。

  3、引數格式轉換

  應當指出,MATLAB所有的計算都是基於一種名為mxArray的資料結構之上的,所有的浮點數、向量或者是矩陣在MATLAB當中都是通過mxArray結構來進行儲存和傳遞的。當然,MATLAB所提供的所有數學函式也都是基於這樣一種資料結構進行運算的。所以,要使用MATLAB的生成程式碼,就必須將C語言當中常用的浮點數和整數轉換為mxArray結構。

  本例中利用MATLAB函式mxArray *mlfScalar(double v)和函式double *mxGetPr(mxArray *)來實現引數格式轉換。函式mlfScalar()將double型變數存入一個新建的mxArray結構中,並返回指標,而函式mxGetPr()將mxArray結構儲存的實數的實部取出。至於其它引數轉換方法可參看參考文獻3中的相關部分。

  最終可以編寫這樣一個利用了MATLAB數學函式並實現計算的函式:

double Mmessay(double ina, double inb) {
 mxArray *a,*b,*c; //三個用於MATLAB數學函式計算的引數
 double *outc; //計算結果變數 
 a=mlfScalar((double)ina); //利用mlfScalar()進行型別轉換
 b=mlfScalar((double)inb);
 mlfAssign(&c, mclPlus(mlfSqrt(mclVv(a, "a")), mlfSqrt(mclVv(b, "b"))));
 outc=mxGetPr(c); //c獲得結果的實部,即結果
 mxDestroyArray(a); //釋放空間
 mxDestroyArray(b);
 mxDestroyArray(c);
 return *outc;


  到此,整個翻譯過程完成,但是還不能直接呼叫。在這個函式當中運用到了MATLAB的數學庫函式mlfSqrt()、mlcPlus()和資料轉換函式mlfScalar()、mxGetPr()。由於這些函式是固化在連結庫當中的,為了連線執行,必須加入幾個庫檔案和幾個靜態連結庫lib檔案。所需要的庫檔案為mcc命令生成的messay.c檔案當中所加入的庫檔案,一般為libmatlb.h,而需要加入的靜態連結庫檔案如下:

libmat.lib,libmatlb.lib,libmex.lib,libmx.lib 

  如果沒有以上檔案,可以用VC的lib命令將MATLAB相應的def檔案轉化為lib檔案,轉化格式為lib /def:filename.def /machine:ix86 /out:filename.lib。