MATLAB 与C/ C + + 、FORTRAN语言混合编程摘要:对MATLAB 与C/ C + + 和FORTRAN 语言进行混合编程的常用方法进行了介绍,分析了其实现方式和各自的利弊,并用实例对MEX 文件实现方式进行了较详细的论述.关键词: MATLAB ; C/ C + + ; FORTRAN ; 混合编程中图分类号: TP313 文献标识码: A 文章编号:16722948X(2004) 0620547205 1 混合编程的意义及其实现方式1. 1 混合编程的意义MATLAB 语言具有功能强大、开发效率高等诸多优点, 已在工程实际中得到广泛应用, 但是与FORTRAN、C/ C + + 等语言相比,其执行效率较低,特别是当程序中含有大量循环语句(例如迭代计算)时,MATLAB 就有些力不从心, 速度很慢, 而运用FORTRAN 等擅长数值计算语言进行编程,其运行效率高. 一方面,如果放弃MATLAB 强大功能和数量众多的应用工具箱,无疑是资源的极大浪费. 另一方面,针对工程实际,人们用FORTRAN、C/ C + + 语言已编写了大量实用程序,如果将其重新改写成M 文件移植到MATLAB 环境中,不仅要花费大量的时间和精力,而且有时还降低了其运行效率. 可否将二者优势互补呢? 混合编程就是其有效的解决途径.1. 2 混合编程的实现正是考虑到上面这些原由,MATLAB 系统提供了其应用程序接口(Application Program Interface) 来解决这些问题. API 主要包括3 部分:MEX 文件———外部程序调用接口,用来在MATLAB 环境下调用FORTRAN、C/ C + + 语言编写的程序;MAT 文件应用程序———数据输入输出接口,用于MATLAB 系统与外部环境之间互传数据; 计算引擎函数库———MATLAB 处于后台作为一个计算引擎,与其它应用程序建立客户机/ 服务器关系,在其它应用程序中调用[1 ,2 ] .1. 2. 1 MEX 文件MEX 文件是按照一定格式,用FORTRAN 或C/C + + 语言编写的源程序,在MATLAB 下借助相应的编译器,生成的动态链接函数的统称. 在Windows操作系统下,是用MATLAB 附带的批处理mex. bat来编译生成文件后缀名为. dll (Dynamic Link Li2brary) 动态链接库文件,该文件可在MATLAB 环境下,像命令函数一样直接运行和调用,使用起来极为方便. 采取MEX 文件方式,是重复利用已有FOR2TRAN、C/ C + + 程序,让MATLAB 和FORTRAN、C/ C + + 语言优势互补的最有效和常用的方式,但不足的是其开发的程序只能在MATLAB 环境下运行.本文将详细的论述基于Windows 平台上其实现过程.1. 2. 2 MAT 文件应用程序MATLAB 数据存储的默认文件名后缀为. mat ,习惯上称该格式的文件为MAT 文件, MAT 文件应用程序提供了一种方法让MATLAB 与其它软件进行数据输入输出.1. 2. 3 MATLAB 计算引擎MATLAB 引擎采用客户机/ 服务器的计算模式,通过对Activex 技术的支持,实现VC 应用程序(客户机) 与MATLAB(服务器) 的动态连接通信. 假如用户想以较短的时间开发前台为VC + + 产生的用户界面,后台由MATLAB 计算分析的应用程序, 使用MATLAB 引擎是很好的选择. 在实际应用中,MAT2 LAB 作为ActiveX 的自动化服务器,接收通过引擎传来的数据和指令信息并进行相应的处理,然后将结果经过引擎返回给发送请求的客户机. 但这种方式需要MATLAB 在后台的适时运行, 如果用户没有安装MATLAB ,应用程序就无法正常运行,而且应用程序与MATLAB 间通过字符流传递数据和命令参数,整个算法在MATLAB 中执行,从而降低了程序的执行效率,因而其实际应用不多.1. 2. 4 MCC 和MATCOM前面提到的几种方式都是以MATLAB 为主,程序的运行都离不MATLAB 环境. 除此之外,另一种方式就是将MATLAB 语言程序翻译成C/ C + + 语言代码,再用C/ C + + 语言的方式进行开发. MAT2 LAB 自己提供了C 语言翻译程序mcc , 另一种是原第3 方公司MathTools 开发的MATCOM. 后者出现较早,功能远比MATLAB 自己的翻译程序强大,所以MathTools 公司已经被MathWorks 公司收购,并已将其开发技术融于新推出的MATLAB 6. 0 (Re2 lease 12) 中. 但二者都不完善,有大量的MATLAB函数及数据类型是不能兼容变换的,所以有时会发现将简洁的MATLAB 程序翻译成C 语言程序很晦涩.翻译后的C 程序几乎不适合手动去维护,更谈不上升级了[3 ] .2 C/ C + + 语言MEX文件的实现C/ C + + 语言MEX 文件的实现包括,源程序的编辑、MEX 编译和调试. 在编译和调试前要进行编译器的配置.2. 1 C/ C+ + 语言MEX文件的编写C/ C + + 语言MEX 文件的编写格式,除了要遵循C/ C + + 语言语法外,还须要加入用于MATLAB和C/ C + + 语言通信协议———入口子程序. 我们首先看一个极简单的C 语言MEX 文件,该程序的作用是两个数求和,源程序如下:/ / 示例程序myplus. c :求两个Double 数之和# include ”mex. h”/ 3 计算功能子程序3 /void myplus (double y[ ] ,double x[ ] ,double z[ ]) {y[0 ] = x[0 ] + z[0 ] ;}/ 3 以下是入口子程序3 /void mexFunction(int nlhs ,mxArray 3 plhs[ ] ,int nrhs ,const mxArray 3 prhs[ ]){double 3 x , 3 y , 3 z ;int mrows0 ,ncols0 ;int mrows1 ,ncols1 ;/ 3 检查输入输出变量个数3 /if (nrhs ! = 2)mexErrMsgTxt (”Two input s arquired”) ;elseif ( nlhs > 1) mexErrMsgTxt ( ”Too many output argument s”) ;/ 3 输入量必须是两个非复数double 类型3 /mrows0 = mxGetM(prhs[0 ]) ;ncols0 = mxGetN(prhs[0 ]) ;if ( ! mxIsDouble (prhs [ 0 ]) | | mxIsComplex (prhs [0 ]) | | ! (mrows0 = = 1 & &ncols0 = = 1) ) mexErrMsgTxt ( ”Input s must be all noncomplex scalar double. ”) ;mrows1 = mxGetM(prhs[1 ]) ;ncols1 = mxGetN(prhs[1 ]) ;if ( ! mxIsDouble (prhs [ 1 ]) | | mxIsComplex (prhs [1 ]) | | ! (mrows1 = = 1 & &ncols1 = = 1) ) mexErrMsgTxt ( ”Input s must be all noncomplex scalar double. ”) ;if (mrows0 ! = mrows1| | ncols0 ! = ncols1) mexErrMsgTxt ( ”Input s must be same dimen2sion. ”) ;/ 3 为返回参数创建矩阵3 /plhs [ 0 ] = mxCreateDoubleMat rix ( mrows0 ,ncols0 ,mxREAL) ;x = mxGet Pr (prhs[0 ]) ;z = mxGet Pr (prhs[1 ]) ;548 三峡大学学报(自然科学版) 2004 年12 月y = mxGet Pr (plhs[0 ]) ;/ 3 调用计算功能子程序myplus () 3 /myplus (y ,x ,z) ;}上面程序为一典型的C 语言MEX 文件,程序由两部分构成:一个计算功能子程序(myplus () 函数) 和一个入口子程序(mexFunction () 函数) . 顾名思义,计算功能子程序包含所有实际所需完成的功能、算法,我们已有的或现编的C/ C + + 、FORTRAN 程序就被当做计算功能子程序使用,它由入口子程序调用. 入口子程序是MATLAB 系统和外部程序之间沟通的桥梁,主要用来完成两者之间的通信. 上面示例程序中,mexFunction () 函数有大量语句是用于检查变量的数据类型等辅助性工作,这是必要的,因为MAT2LAB 语言不像C/ C + + 等语言变量使用前须声明,对类型的检查可以避免许多错误的发生.下面简要的说明一下上面程序中用到的MAT2LAB API 函数,它们在mex. h 或mat rix. h 中声明. mexFunction () ,入口子程序函数,其格式如下:void mexFunction(int nlhs ,mxArray 3 plhs[ ] ,intnrhs ,const mxArray 3 prhs[ ]){⋯⋯/ / 一些必要的代码,用来完成MATLAB 系统与计算功能子程序之间的通信}其参数的含意为:nrhs 和nlhs ,整型变量,分别为调用MEX 文件时输入、输出参数的个数. prhs、plhs ,指针数组,其元素分别为指向输入、输出参数的指针. mexErrMsgTxt () ,用于输出错误信息,并返回到MATLAB 命令提示符下.mxGetM() 和mxGetN ( ) ,获得矩阵的行数和列数,参数为指向矩阵的指针,如程序中的mrows0 =mxGetM(prhs[0 ]) 的作用为:得到第一个输入实参的行数,并赋值给整型变量mrows0.mxIsDouble () 、mxIsComplex () ,判断矩阵是否为双精度型、复数型. 输入参数为矩阵指针,返回值为BOOL 值.mxCreateDoubleMat rix(int m ,int n ,mxComplex2ity complexFlag) ,创建一个未赋值的双精度矩阵,m ,n 为创建矩阵的行、列数,complexFlag 为标识是实数还是复数. 该函数返回所创建矩阵的指针.mxGet Pr () 获得矩阵实数部分的指针,输入参数为矩阵的指针,返回值为矩阵实数部分的双精度指针.MATLAB API 函数还包含其它许多接口函数,分为mx2函数和mex2函数,详细情况可查阅相关文献.MEX 源程序编写完成后,还要经过编译后才能生成dll 文件,供MATLAB 或其它程序调用,编译前要对MATLAB 进行编译器的配置.2. 2 编译器的配置编译器的配置是通过MATLAB 的配置文件(mexopt s. bat ) 进行的,其具体过程为: 在MATLAB 命令窗口下键入:mex2steup ,随后系统弹出一个DOS 窗口,按照提示一步步选择完成即可. 该命令可带许多参数,可针对不同的操作系统进行多种配置[2 ,3 ] . 2. 3 C/ C+ + 语言MEX文件的编译编译方法很简单,直接在MATLAB 命令提示符下键入:mex filename ,其中filename 为需编译的源程序名. 如果提示有错误信息,需查错,修改源程序、调试. 直到没有错误信息提示. 编译通过生成的可执行的dll 文件,可在MATLAB 命令提示符下或其它程序中调用.3 FORTRAN语言MEX文件的实现FORTRAN 语言MEX 文件的实现步骤和C/ C+ + 语言MEX 文件大体相同.3. 1 FORTRAN 语言MEX 文件的编写MATLAB 提供了C/ C + + 和FORTRAN 两种语言的接口,基于FORTRAN 语言和前面讲到的基于C/ C + + 语言的MEX 文件在实现方式上相差不大. 我们先还是看一下前面程序用FORTRAN 语言MEX 文件来实现的源程序.! 示例程序myplus. f :求两个数之和! 计算功能子程序subroutine myplus (y ,x ,z)! 变量声明real 3 8 x ,y ,zy = x + zreturnend! 以下是入口子程序subroutine mexFunction(nlhs ,plhs ,nrhs ,prhs) ! 参数声明integer nlhs ,nrhs ,plhs ( 3 ) ,prhs ( 3 )! 调用API 库函数的声明integer mxGet Pr ,mxCreateFullinteger mxGetM ,mxGetN ,mxIsNumeric! 程序内部使用变量的声明第26 卷第6 期陈建平等MATLAB 与C/ C + + 、FORTRAN 语言混合编程549 integer xpr ,ypr ,zprinteger mrows ,ncols ,sizereal 3 8 x ,y ,z! 检查输入输出变量个数if (nrhs. ne. 2) thencall mexErrMsgTxt (’Two input s arquired’)elseif (nlhs. gt . 1) thencall mexErrMsgTxt ( ’Too many output argu2ment s’)endif! 输入量必须是两个数mrows = mxGetM(prhs (1) )ncols = mxGetN(prhs (1) )size = mrows 3 ncolsif (mxIsNumeric (prhs (1) ) . eq. 0) thencall mexErrMsgTxt (’Input s must be a number’)endifmrows = mxGetM(prhs (2) )ncols = mxGetN(prhs (2) )size = mrows 3 ncolsif (mxIsNumeric (prhs (2) ) . eq. 0) thencall mexErrMsgTxt (’Input s must be a number’)endif! 为输出参数创建矩阵plhs (1) = mxCreateFull (mrows ,ncols ,0)xpr = mxGet Pr (prhs (1) )zpr = mxGet Pr (prhs (2) )ypr = mxGet Pr (plhs (1) )! 将数据指针转换成双精度型call mxCopyPt r ToReal8 (xpr ,x ,size)call mxCopyPt r ToReal8 (zpr ,z ,size)! 调用计算功能子程序mypluscall myplus (y ,x ,z)! 将计算结果传给输出数据指针call mxCopyReal8ToPt r (y ,ypr ,size)returnend该程序的结构和内容与前面myplus. c 大致相同,也是由两部分:一个计算功能子例行程序和一个入口子例行程序构成,其程序中参数和变量大多相同,这里就不一一再介绍了. 但值得一提的是, FOR2TRAN 和C/ C + + 语言语法规则相差较大,在C/ C ++ 语言中对字符大小写是敏感的,而FORTRAN 语言中大小写是一样的;C/ C + + 语言中数组是按行存储,数组下标是从0 开始计数的,而FORTRAN 语言中数组是按列存储,数组下标从1 开始. C/ C + + 语言几乎支持所有的数据类型,支持头文件,操作很灵活. 而FORTRAN 语言,不支持指针,参数传输较麻烦[1 ] .3. 2 FORTRAN语言MEX文件的编译和C/ C + + 语言MEX 文件一样,编译前需进行编译器的配置,方法同前,只是选的编译器不同(例如Compaq Visual Fort ran version 6. 6) . 编译的过程也一样,MATLAB6 的编译命令(不再区分C/ C + + 文件用cmex. bat ,FORTRAN 用fmex. bat) 统一使用mex.bat 批处理命令,其后的文件名须带扩展名.4 Visual Studio IDE 下MEX文件的建立和调试4. 1 Visual Studio 的配置前面使用的mex 文件的使用方式,类似在DOS下程序开发方式,程序编辑、编译、调试和执行分开,每次只能创建一个文件,需要来回切换MATLAB 命令窗口和编辑窗口,操作较麻烦. VC 是在Windows环境下的优秀开发平台,将MATLAB 和VC 强强联手,无疑是非常好的混合编程方式. 下面就简要介绍一下如何在VC 的IDE( Integrated Development Envi2 ronment) 中编译MEX 程序. 为了表述的方便,我们以MATLAB6. 5 (安装在C: \ matlab6p5) 和Visual C ++ 6. 0 (安装在D : \ Program Files \ Microsoft Visual Studio) 为例,可以分为以下5 步[4 ,5 ] :①用VC 创建一个工程(假定名称为myproject) ,类型选择Win32 Dynamic - link Library ,并将自己的MEX源程序和mexversion. rc (在C: \ MATLAB6p5\ extern \ include 下) 加入到工程.②创建一个与工程同名的定义文件(myproject .def) ,内容如下:L IBRARY myproject . dllEXPORTS mexFunction(如果是FORTRAN 该行改为EXPORTS -MEXFUNCTION @16 )并加入定义文件myproject . def 到工程③定位库文件( . lib) 位置. 具体操作为:选择VC下拉菜单Tools/ Options ⋯,在弹出的对话框Show di2rectories for 下拉框中选择Library files ,在下部的Di2 rectories : 中添加C: \ MATLAB6p5 \ extern \ lib \win32 \ microsoft \ msvc60 目录. 然后选择VC 下拉菜单Project/ Settings ⋯, 在弹出的对话框中选择550 三峡大学学报(自然科学版) 2004 年12 月Link 选项卡,在Category 栏中选择general 选项,在出现的Object/ library modules : 框中填入libmx. lib , libmex. lib , and libmat . lib.④加入MATLAB include 目录. 具体操作为:选择VC 下拉菜单Tools/ Options ⋯,在弹出的对话框Show directories for 下拉框中选择Include files ,在下部的Directories : 中添加C: \ MATLAB6p5 \ extern\ include 目录. 然后选择VC 下拉菜单Project/ Set2tings ⋯, 在弹出的对话框中选择C/ C + + 选项卡,在Category 栏中选择Preprocessor 选项,在出现的Pre2 processor definitions : 框中填入MATLAB-MEXFILE.⑤最后就是调试运行配置. 具体操作为:选择VC下拉菜单Project/ Settings ⋯,在弹出的对话框选择Debug 选项卡,在Category 栏中选择General 选项,在出现的Executable for debug session :框中填入C: \ MATLAB6p5 \ bin \ win32 \ matlab. exe.4. 2 在Visual Studio 中使用MATLAB add - inMATLAB6. X为Visual Studio IDE 提供了add -in ,该add - in 使MATLAB 的M - files 非常容易的就可加入到VC 环境中,使VC 和MATLAB 很好的融合. 不过要使用该插件需要简单的配置. 具体操作如下:使用前面提到的mex - steup 命令进行编译器的配置, 选择VC 作为编译器后, 该命令自动装载MATLAB add - in. 然后选择VC 下拉菜单Tools/Customize ⋯, 在弹出的对话框中勾选MATLAB add- in 复选框. 随后VC 就出现了如图1 所示的工具条,其中第一个按钮的功能就是用来将M - files 添加到Visual Studio IDE 中的.图1 图标示例5 结语本文对MATLAB 与C/ C + + 和FORTRAN 语言进行混合编程的常用4 种方法进行了论述. 4 种方法各有其优势,又各有不足. 其中MEX 文件的方式,特别是Visual Studio IDE 下混合编程,将MATLAB和Visual Studio 开发系统相接合,以其功能强大、操作便利和利于升级维护,具有广泛的使用价值.参考文献:[1 ] 刘志俭. MATLAB 应用程序接口用户指南[M] . 北京:科学技术出版社,2000.[2 ] 飞思科技产品研发中心. MATLAB6. 5 应用程序接口编程[M] . 北京:电子工业出版社,2003.[3 ] 薛定宇. 科学运算语言MATLAB5. 3 程序设计与应用[M] . 北京:清华大学出版社,2000.[4 ] 王振义. MATLAB 和Visual C + + 的混合编程[J ] . 雁北师范学院学报,2002 ,18 (2) :26~29.[5 ] 马海阳,王艳华,孙道恒. MATLAB 的VC 编程接口浅析[J ] . 信息技术,2003 ,27 (3) :55~57.[责任编辑张莉]第26 卷第6 期陈建平等MATLAB 与C/ C + + 、FORTRAN 语言混合编程551__。