C语言实现MATLAB 6.5中M文件的方法
摘要:本文著重描述了運(yùn)用MATLAB命令將M文件翻譯為C語言程序,并修改為可直接調(diào)用的C語言函數(shù)的方法,使用該方法所需要注意的方法局限性和MATLAB版本差異的影響。運(yùn)用該方法將能夠使C語言能直接使用MATLAB當(dāng)中已經(jīng)完成的數(shù)學(xué)計(jì)算功能,大大擴(kuò)充了C語言的數(shù)學(xué)計(jì)算功能和開發(fā)效率。
關(guān)鍵詞:MATLAB;M文件;C語言接口
眾所周知,MATLAB是一個(gè)功能強(qiáng)大的數(shù)學(xué)軟件,擅長于用矩陣運(yùn)算完成各種數(shù)學(xué)功能。但是其程序需要在MATLAB環(huán)境下解釋執(zhí)行,效率不高。如果能將它強(qiáng)大的函數(shù)庫用于C語言,利用C來編譯執(zhí)行,MATLAB將能發(fā)揮更大的作用。所以,MATLAB從5.0開始已經(jīng)提供了與外部C/C++程序的應(yīng)用程序接口,為利用C語言調(diào)用MATLAB的函數(shù)提供了可能。但是MATLAB的接口發(fā)展很快,到MATLAB 6.5已經(jīng)提供了對(duì)VC 7.0的支持,同時(shí)對(duì)C的接口相對(duì)于5.X版本有了一定的改變。
在MATLAB當(dāng)中,我們利用M文件來實(shí)現(xiàn)函數(shù),每一個(gè)M文件實(shí)現(xiàn)一個(gè)單獨(dú)的功能,這一點(diǎn)和C語言當(dāng)中的函數(shù)是相互對(duì)應(yīng)的。所以,如果我們能將MATLAB中的M文件轉(zhuǎn)化為C語言下的一個(gè)單個(gè)函數(shù),就能實(shí)現(xiàn)MATLAB中相應(yīng)的功能。
實(shí)現(xiàn)方法
整個(gè)過程可分為三個(gè)主要部分,用MATLAB將M文件翻譯為C語言文件,從生成的C語言文件提取出有用語句,編寫數(shù)據(jù)轉(zhuǎn)換程序?qū)崿F(xiàn)參數(shù)格式轉(zhuǎn)換。整個(gè)過程最終將把M文件翻譯成C語言當(dāng)中的一個(gè)具有相同功能的函數(shù),供其它的程序調(diào)用。
本文用一個(gè)最簡(jiǎn)單的M文件來示例:
文件名:messay.m
function c=messay()
a=3.4;
b=5.6;
c=sqrt(a)+sqrt(b);
該m文件實(shí)現(xiàn)了計(jì)算
1、將M文件編譯為C語言文件
為了將M文件翻譯為C語言文件,需要進(jìn)行一定的設(shè)置,這里假設(shè)編寫C語言的環(huán)境為VC6.0,在MATLAB命令提示符下輸入mex -setup和mbuild -setup命令,在相應(yīng)選項(xiàng)中選擇Microsoft Visual C/C++即可。
在MATLAB命令行中使用mcc命令將messay.m翻譯為C代碼。
mcc -m messay.m
其中的參數(shù)-m代表mcc命令將把m文件翻譯成C語言的代碼。
翻譯命令將在messay.m所在的文件夾下生成三個(gè)C語言文件:messay.h,messay.c和messay_main.c。其中messay_main.c提供了main()函數(shù);messay.h提供了整個(gè)程序的函數(shù)聲明;messay.c包含了MATLAB生成的功能函數(shù)。這三個(gè)文件當(dāng)中,messay.c中包含了我們所需要的數(shù)學(xué)函數(shù)。
2、提取有用語句
通過分析,發(fā)現(xiàn)由mcc生成的代碼內(nèi)部參數(shù)傳送方式由MATLAB鏈接庫規(guī)定,難以改動(dòng),因此需要提取有用的代碼,并更改生成代碼的參數(shù)傳遞方式。同時(shí)從生成代碼的注釋中可以看出,真正蘊(yùn)含M文件功能實(shí)現(xiàn)的代碼段都在Mmessay()函數(shù)當(dāng)中(該函數(shù)名的默認(rèn)構(gòu)造方式為前綴M加上M文件的文件名),而其它的生成函數(shù)僅實(shí)現(xiàn)參數(shù)傳遞和標(biāo)準(zhǔn)化接口服務(wù)的功能。
所以提取代碼的具體方法是利用messay.c當(dāng)中生成的static mxArray * Mmessay(int nargout_)函數(shù),對(duì)該函數(shù)進(jìn)行修改,而其他的生成函數(shù)都可以忽略不用。原生成的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;
}
在生成代碼當(dāng)中,mclSetCurrentLocalFunctionTable和mclSetCurrentLocalFunctionTable函數(shù)為兩個(gè)外部函數(shù),將參數(shù)傳給外部,與其相關(guān)的部分都對(duì)C程序使用數(shù)學(xué)函數(shù)沒有影響。最終實(shí)際有用并執(zhí)行運(yùn)算的只有一句:
mlfAssign(&c, mclPlus(mlfSqrt(mclVv(a, "a")), mlfSqrt(mclVv(b, "b"))));
實(shí)際上,由MATLAB翻譯的C語句中,大部分的和實(shí)際計(jì)算有關(guān)的語句和自生成的函數(shù)都以mlf開頭,所以尋找有用語句的簡(jiǎn)單方法就是直接尋找mlf為前綴的代碼。
3、參數(shù)格式轉(zhuǎn)換
應(yīng)當(dāng)指出,MATLAB所有的計(jì)算都是基于一種名為mxArray的數(shù)據(jù)結(jié)構(gòu)之上的,所有的浮點(diǎn)數(shù)、向量或者是矩陣在MATLAB當(dāng)中都是通過mxArray結(jié)構(gòu)來進(jìn)行存儲(chǔ)和傳遞的。當(dāng)然,MATLAB所提供的所有數(shù)學(xué)函數(shù)也都是基于這樣一種數(shù)據(jù)結(jié)構(gòu)進(jìn)行運(yùn)算的。所以,要使用MATLAB的生成代碼,就必須將C語言當(dāng)中常用的浮點(diǎn)數(shù)和整數(shù)轉(zhuǎn)換為mxArray結(jié)構(gòu)。
本例中利用MATLAB函數(shù)mxArray *mlfScalar(double v)和函數(shù)double *mxGetPr(mxArray *)來實(shí)現(xiàn)參數(shù)格式轉(zhuǎn)換。函數(shù)mlfScalar()將double型變量存入一個(gè)新建的mxArray結(jié)構(gòu)中,并返回指針,而函數(shù)mxGetPr()將mxArray結(jié)構(gòu)保存的實(shí)數(shù)的實(shí)部取出。至于其它參數(shù)轉(zhuǎn)換方法可參看參考文獻(xiàn)3中的相關(guān)部分。
最終可以編寫這樣一個(gè)利用了MATLAB數(shù)學(xué)函數(shù)并實(shí)現(xiàn)計(jì)算的函數(shù):
double Mmessay(double ina, double inb) {
mxArray *a,*b,*c; //三個(gè)用于MATLAB數(shù)學(xué)函數(shù)計(jì)算的參數(shù)
double *outc; //計(jì)算結(jié)果變量
a=mlfScalar((double)ina); //利用mlfScalar()進(jìn)行類型轉(zhuǎn)換
b=mlfScalar((double)inb);
mlfAssign(&c, mclPlus(mlfSqrt(mclVv(a, "a")), mlfSqrt(mclVv(b, "b"))));
outc=mxGetPr(c); //c獲得結(jié)果的實(shí)部,即結(jié)果
mxDestroyArray(a); //釋放空間
mxDestroyArray(b);
mxDestroyArray(c);
return *outc;
}
到此,整個(gè)翻譯過程完成,但是還不能直接調(diào)用。在這個(gè)函數(shù)當(dāng)中運(yùn)用到了MATLAB的數(shù)學(xué)庫函數(shù)mlfSqrt()、mlcPlus()和數(shù)據(jù)轉(zhuǎn)換函數(shù)mlfScalar()、mxGetPr()。由于這些函數(shù)是固化在鏈接庫當(dāng)中的,為了連接執(zhí)行,必須加入幾個(gè)庫文件和幾個(gè)靜態(tài)鏈接庫lib文件。所需要的庫文件為mcc命令生成的messay.c文件當(dāng)中所加入的庫文件,一般為libmatlb.h,而需要加入的靜態(tài)鏈接庫文件如下:
libmat.lib,libmatlb.lib,libmex.lib,libmx.lib
如果沒有以上文件,可以用VC的lib命令將MATLAB相應(yīng)的def文件轉(zhuǎn)化為lib文件,轉(zhuǎn)化格式為lib /def:filename.def /machine:ix86 /out:filename.lib。
方法的局限
使用本文所用的方法可以將M文件翻譯為C語言的函數(shù),但是要受到兩個(gè)因素的制約。
1、功能的實(shí)現(xiàn)受到MATLAB C函數(shù)庫的限制
這種翻譯的機(jī)制是由MATLAB提供的,mcc命令能直接翻譯的函數(shù)也僅局限于MATLAB原有的函數(shù)。因?yàn)檫@些函數(shù)已經(jīng)被MATLAB6.5編譯好,一般以mlf為前綴,存于動(dòng)態(tài)鏈接庫當(dāng)中并可被C語言直接調(diào)用。這些函數(shù)在參考文獻(xiàn)4中可以查到。而超出了這個(gè)范圍的函數(shù),并在M文件當(dāng)中被嵌套使用,在用mcc進(jìn)行翻譯的時(shí)候,mcc將在函數(shù)名前加上前綴mlf,并進(jìn)一步翻譯該函數(shù)。
但是,這種翻譯受到MATLAB參數(shù)傳遞的限制,而不能直接調(diào)用,在編譯時(shí)會(huì)出現(xiàn)找不到相應(yīng)的外部函數(shù)的錯(cuò)誤。解決辦法是手動(dòng)將所有被翻譯的函數(shù)進(jìn)行參數(shù)傳遞方式的調(diào)整。如果M文件當(dāng)中包含的函數(shù)被嵌套翻譯的層數(shù)很深,這樣的工作量是巨大而且不可接受的。
同時(shí)很多工具箱當(dāng)中定義的函數(shù)也是不能使用這種方法進(jìn)行翻譯的。MATLAB的工具箱更新速度很快,而相應(yīng)的MATLAB C的函數(shù)庫有一定滯后,導(dǎo)致很多最新的工具箱當(dāng)中的函數(shù)是不能被翻譯的。
2、翻譯本身存在的限制
因?yàn)檫@種翻譯是遵守C語言要求的,因而對(duì)于內(nèi)存分配要求和C語言不同的函數(shù)和一些關(guān)于圖形顯示類型的函數(shù)(包括大量的GUI相關(guān)函數(shù))也不能被正確的翻譯。例如mash.m和step.m這兩個(gè)較常用的MATLAB函數(shù),由于上述的限制,就不能用本方法進(jìn)行翻譯。
對(duì)于上述的問題,可以利用在C程序當(dāng)中運(yùn)用MATLAB引擎的方法動(dòng)態(tài)調(diào)用MATLAB的庫函數(shù),基本上可以解決上述所有的函數(shù)不能被正確翻譯和圖形顯示的問題。但是,運(yùn)用MATLAB引擎的方法需要利用ActiveX的自動(dòng)化服務(wù)器,在運(yùn)行的時(shí)候程序會(huì)在后臺(tái)執(zhí)行一個(gè)MATLAB的線程而不能完全脫離MATLAB的環(huán)境,也就意味著在純C的環(huán)境下是不能運(yùn)用的,必須要先安裝MATLAB并能夠在運(yùn)行時(shí)支持多線程工作。具體的方法可以參閱參考文獻(xiàn)3。
MATLAB 5.X和MATLAB 6.5的區(qū)別
對(duì)于本方法有以下幾點(diǎn)區(qū)別需要注意:
(1)程序當(dāng)中所需的庫文件由5.X版本的matrix.h、mcc.h、matlab.h改為mex.h、libmatlb.h、libmatlbm.h等庫文件。
(2)程序所需要加入的靜態(tài)鏈接庫文件由5.X需要的libmmfile.lib、libmatlb.lib、libmcc.lib、libmx.lib改為libmat.lib、libmatlb.lib、libmex.lib、libmx.lib四個(gè)文件。
(3)API函數(shù)改動(dòng)很多,雖然數(shù)學(xué)函數(shù)庫即mlf前綴的函數(shù)少有改動(dòng),但是關(guān)于變量建立,內(nèi)存管理和數(shù)據(jù)類型轉(zhuǎn)換的函數(shù)發(fā)生改變,即很多原mcc前綴的函數(shù)改為用mx為前綴的函數(shù)代替,使得很多5.X翻譯的C程序代碼不能在6.5相應(yīng)的庫下運(yùn)行通過。
(4)6.5版本中直接增加了在VC環(huán)境下對(duì)M文件的支持。在執(zhí)行mbuild -setup的配置命令后,MATLAB在VC中提供了MATLAB Project Wizard,可在VC環(huán)境下直接建立MATLAB的工程來翻譯M文件。但是這種翻譯方法在遇到未定義函數(shù)嵌套時(shí)將錯(cuò)誤的把函數(shù)名翻譯為變量名,而mcc命令將進(jìn)一步翻譯內(nèi)部嵌套的函數(shù)。
總結(jié)
以上是生活随笔為你收集整理的C语言实现MATLAB 6.5中M文件的方法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 欧拉角与四元数
- 下一篇: 3DSlicer27:OpenIGTLi