Matlab与C/C++混合编程接口及应用摘要:Matlab具有很强的数值计算和分析等能力,而C/C++是目前最为流行的高级程序设计语言,两者互补结合的混合编程在科学研究和工程实践中具有非常重要的意义。从Matlab调用C/C++代码及C/C++调用m文件两方面,深入地研究了它们之间混合编程的原理和实现机制,并且给出了具体条件下的混合编程方法和步骤。实验表明,给出的Matlab与C/C++混合编程接口及应用方法是有效、实用的。1引言Matlab是当前应用最为广泛的数学软件,具有强大的数值计算、数据分析处理、系统分析、图形显示甚至符号运算等功能[1]。利用这一完整的数学平台,用户可以快速实现十分复杂的功能,极大地提高工程分析计算的效率[2][3]。但与其他高级程序[3]相比,Matlab程序是一种解释执行程序,不用编译等预处理,程序运行速度较慢[4]。C/C++语言是目前最为流行的高级程序设计语言之一[5]。它可对操作系统和应用程序以及硬件进行直接操作,用C/C++语言明显优于其它解释型高级语言,一些大型应用软件如Matlab就是用C语言开发的。在工程实践中,用户经常遇到Matlab与C/C++混合编程的问题。本文基于Matlab6.5和VC6.0开发环境,在Windows平台下就它们之间的混合编程问题进行深入研究并举例说明。2Matlab调用C/C++Matlab调用C/C++的方式主要有两种:利用MEX技术和调用C/C++动态连接库。在Matlab与C/C++混合编程之前,必须先对Matlab的编译应用程序mex和编译器mbuild进行正确的设置[1]:对Matlab编译应用程序mex的设置:Mex–setup.对Matlab编译器mbuild的设置:Mbuild–setup.2.1调用C/C++的MEX文件MEX是MatlabExecutable的缩写,它是一种“可在Matlab中调用的C(或Fortran)语言衍生程序”[6]。MEX文件的使用极为方便,其调用方式与Matlab的内建函数完全相同,只需在Matlab命令提示符下键入MEX文件名即可。一个C/C++的MEX源程序通常包括4个组成部分,其中前3个是必须包含的内容,第4个则根据所实现的功能灵活选用:(1)#include“mex.h”;(2)MEX文件的入口函数mexFunction,MEX文件导出名必须为mexFunction函数;(3)mxArray;(4)API函数通过简单的例子说明C/C++的MEX源程序编写和调用过程:#includemex.hvoidtimeSTwo(doubley[],doublex[]){y[0]=2.0*x[0];}voidmexFunction(intnlhs,mxArray*plhs[],intnrhs,constmxArray*prhs[]){double*x,*y;intmrows,ncols;if(nrhs!=1)mexErrMsgTxt(Oneinputrequired.);elseif(nlhs1)mexErrMsgTxt(Toomanyoutputarguments);mrows=mxGetM(prhs[0]);ncols=mxGetN(prhs[0]);if(!mxIsDouble(prhs[0])||mxIsComplex(prhs[0])||!(mrows==1&&ncols==1))mexErrMsgTxt(Inputmustbeanoncomplexscalardouble.);plhs[0]=mxCreateDoubleMatrix(mrows,ncols,mxREAL);x=mxGetPr(prhs[0]);y=mxGetPr(plhs[0]);timestwo(y,x);}可在matlab中编译,也可以直接在C++环境中编译:1).(在matlab中)用指令mextimestwo.c编译此文件,然后在MATLAB命令行下调用生成的MEX文件即可。2).(在VC2008中)和一般c++一样编译后,就会产生dll,这样可以直接在Matlab中用了,或者copy且更改后缀名.mexw32即可。(因为MatlabR2010b以后版本可能不支持调用dll为后缀的mex文件了)2.2调用C/C++动态连接库(即:一般普通的C程序dll没有用mex的接口函数)Matlab提供对动态连接库DLL文件的接口[7]。利用该接口,可在Matlab中调用动态连接库导出的函数。Matlab对DLL的接口支持各种语言编写的DLL文件。在调用DLL文件之前,需要准备函数定义的头文件。对于C/C++语言开发的DLL文件,可使用源程序中相应的头文件;而对于其他语言开发的DLL,则要手工准备等效的C语言函数定义头文件。在Matlab中利用动态连接库接口技术通常需要完成以下4个步骤:(1)打开动态连接库文件;(2)为调用函数准备数据;(3)调用动态连接库文件中导出的函数;(4)关闭动态连接库文件。为了实现以上步骤,用到的Matlab函数有:loadlibrary,loadlibrary,calllib,libfunctions,lipointer,libstruct,libisloaded。下面举例说明Matlab调用C/C++动态连接库的方法和步骤:a.在VC环境下,新建工程-win32动态连接库-工程名Test1-empty工程-完成;b.新建-C++源文件-添加a.cpp,内容为:#includea.h_declspec(dllexport)intadd(inta,intb){returna+b;}c.新建-C/C++头文件-添加a.h,内容为:_declspec(dllexport)intadd(inta,intb);然后编译生成Test1.dll动态连接库文件,将Test1.dll和a.h拷到Matlab工作目录下。d.在Matlab命令行下,调用Test.dll:loadlibrary(‘Test1’,’a.h’);x=7;y=8;calllib(‘Test1’,‘add’,x,y);Ans=15unloadlibrary(‘Test1’).调用DLL动态连接库的方法,为Matlab重用工程实践中积累的大量实用C/C++代码提供了一种简洁方便的方法。与调用MEX文件相比,该方法更加简便实用。但是这个接口之支持C,不支持C++库和函数的重载,这种情况下,推荐用MEX-file,若实在要用这种方法(调用C/C++动态连接库),则对于C++要做一些更改,详见,3C/C++调用Matlab在工程实践中,C/C++调用Matlab的方法主要有调用Matlab计算引擎、包含m文件转换的C/C++文件,以及调用m文件生成的DLL文件。3.1利用Matlab计算引擎Matlab的引擎库为用户提供了一些接口函数,利用这些接口函数,用户在自己的程序中以计算引擎方式调用Matlab文件。该方法采用客户机/服务器的方式,利用Matlab引擎将Matlab和C/C++联系起来。在实际应用中,C/C++程序为客户机,Matlab作为本地服务器。C/C++程序向Matlab计算引擎传递命令和数据信息,并从Matlab计算引擎接收数据信息[2]。Matlab提供了以下几个C语言计算引擎访问函数供用户使用[8]:engOpen,engClose,engGetVariable,engPutVariable,engEvalString,engOutputBuffer,engOpenSingleUse,engGetVisible,engSetVisible。下面以C语言编写的、调用Matlab引擎计算方程x3?2x+5=0根的源程序example2.c为例,说明C/C++调用Matlab计算引擎编程的原理和步骤:#includewindows.h#includestdlib.h#includestdio.h#includeengine.hintPASCALWinMain(HANDLEhInstance,HANDLEhPrevInstance,LPSTRlpszCmdLine,intnCmdShow){Engine*ep;mxArray*P=NULL,*r=NULL;charbuffer[301];doublepoly[4]={1,0,-2,5};if(!(ep=engOpen(NULL))){fprintf(stderr,\nCan'tstartMATLABengine\n);returnEXIT_FAILURE;}P=mxCreateDoubleMatrix(1,4,mxREAL);mxSetClassName(P,p);memcpy((char*)mxGetPr(P),(char*)poly,4*sizeof(double));engPutVariable(ep,P);engOutputBuffer(ep,buffer,300);engEvalString(ep,disp(['多项式',poly2str(p,'x'),'的根']),r=roots(p));MESSageBox(NULL,buffer,example2展示MATLAB引擎的应用,MB_OK);engClose(ep);mxDestroyArray(P);returnEXIT_SUCCESS;}在Matlab下运行example2.exe:mex-fexample2.c。运行结果如图1所示:利用计算引擎调用Matlab的特点是:节省大量的系统资源,应用程序整体性能较好,但不能脱离Matlab的环境运行,且运行速度较慢,但在一些特别的应用[9](例如需要进行三维图形显示)时可考虑使用。3.2利用mcc编译器生成的cpp和hpp文件Matlab自带的C++Complier--mcc,能将m文件转换为C/C++代码。因此,它为C/C++程序调用m文件提供了另一种便捷的方法。下面举例说明相应步骤:a.新建example3.m:functiony=exmaple3(n)y=0;fori=1:ny=y+i;end保存后在命令窗口中输入:mcc-t-LCpp-hexample3.则在工作目录下生成example3.cpp和example3.hpp两个文件。b.在VC中新建一个基于对话框的MFC应用程序Test2,添加一个按钮,并添加按钮响应函数,函数内容见f步。将上面生成的两个文件拷贝到VC工程的Test2目录下。c.在VC中选择:工程-设置,选择属性表Link选项,下拉菜单中选择Input,在对象/库模块中加入lIBMmfile.liblibmatlb.liblibmx.liblibmat.liblibmatpm.libsgl.liblibmwsglm.liblibmwservices.lib,(后三个为使用Matlab图形库时,需加入)注意用空格分开;而在忽略库中加入msvcrt.lib;d.选择属性表C/C++选项,下拉菜单选General,在预处理程序定义中保留原来有的内容,并添加MSVC,IBMPC,MSWIND,并用逗号隔开。选择下拉菜单的PrecompiledHeaders选项,在“自动使用预补偿页眉”中添加stdafx.h,然后确定。e.选择:工具-选项,属性页选择“目录”,在includefiles加入:C:\MATLAB6p5p1\extern\include,C:\MATLAB6p5p1\extern\include\cpp;然后在Libraryfiles里面加入:C:\MATLAB6p5p1\bin\win32,C:\MATLAB6p5p1\extern\lib\win32\microsoft\msvc60;注意根据用户的Matlab安装位置,修改相应目录。f.在响应函