学 士 学 位 论 文
BACHELOR ’S THESIS 从上面可看出, 这时还可以直接调用MATLAB 的矩阵计算函数, 如求逆inv、求行列式det.
3.6 MATCOM
MATCOM 是由MathTools 公司开发的可以将M 文件转换成相同功能的C 代码的工具软件, 功能比MCC 命令更强大,它在一定程度上解决了代码复用、执行效率和源代码保密等问题。开发人员可以将一些在C 中实现起来比较复杂,而用MATLAB 的库函数更容易解决的底层工作如数值分析等交给MATLAB 来实现, 并通过MATLAB 转换为C 代码, 再加入到C工程中的适当位置。最后生成可以脱离MATLAB 环境独立运行的程序, 开发出具有自主版权的软件。[13][15]
MATLAB包括数学函数和工具箱函数,MATCOM已经将一般数学函数进行编译,可以遵循MATCOM语言规则直接在C中使用;要使用工具箱函数,则需要在MATCOM下编译MATLAB的M文件。
MATLAB 和MCC 命令类似, 在代码转换过程中产生大量的冗余代码,代码可读性差。而且实际执行效率提高得并不多。实践证明, 对MATLAB 中大规模数据处理程序中瓶颈部分用MATLAB或MCC 命令转换成C 代码后速度可以加快约一倍, 而如果用自己编写的C 语言MEX 程序实现, 速度可以提高上百倍。
[11][1]
在C 的程序里直接书写类MATCOM 语句
按照MATCOM 的语法, 在C 中直接书写类MATCOM语句. 例如: void testcom( void) {
InitM(MATCOM VERSION) ; / / 初始化Matcom 进程 Mm x, s, c; / / 定义变量, Mm 为Matcom 的矩阵类 X= colon( 0, 0, 0, 01. 10) ; / / 类似for 循环语句 S= sin( x) ; / / 正弦函数 C= cos( x) ; / / 余弦函数
Plot( (CL( x) , c, x, s, ) ) ; / / 画出正弦和余弦函数 ExitM( ) ; / / 退出Matcom 进程 }
16
学 士 学 位 论 文
BACHELOR ’S THESIS testcom 这个函数是在C 的源程序里直接书写MATCOM 语句, 其中所有的变量x, s, c 都是一个序列数, 而不是一个单独的值. 在过程开始时必须初始化MATCOM进程, 即InitM(MATCOM VERSION) ; 当书写完MATCOM 语句结束过程时, 需要退出MATCOM 进程, 如程序中的exitM( ) . 其中的colon( ) 函数和plot( ) 函数都是MATCOM 下的函数. colon( 0. 0, 0. 01, 10) 类似一个for ( x= 0. 0; x< 10; x= x+ 0. 01) 的循环语句. MATCOM 优于MATLAB 的主要地方是MATCOM 支持图形, 即支持Plot( ) 函数和其他图形函数在C 中直接应用.[17]
4. C语言MEX文件的实现
C语言MEX文件的实现包括,源程序的编译、MEX的编译和调试。在编译和调试前要进行编译器的配置。
4.1 C语言MEX文件的编写
C语言MEX文件的编写格式,除了要遵循C语言语法外,还须要加入用于MATLAB和C 语言通信协议---入口子程序。我们首先看一个极简单的C语言MEX文件,该程序的作用是两个数求和,源程序如下:
/ / 示例程序 myplus. c: 求两个 Double 数之和
# include 0 mex. h0 / * 计算功能子程序* /
void myplus( double y[ ] , double x[ ] , double z[ ] ) {
y[ 0] = x[ 0] + z[ 0] ; }
/ * 以下是入口子程序* /
void mexF unction( int nlhs, mxArray * plhs[ ] , intnrhs, const mxArray * prhs[ ] )
{
17
学 士 学 位 论 文
BACHELOR ’S THESIS double * x, * y, * z; int mrows0, ncols0; int mrows1, ncols1;
/ * 检查输入输出变量个数* / if( nrhs! = 2)
mexErrMsgT xt (0 Two inputs arquired0 ) ; else
if( nlhs> 1) mexErrMsgT xt ( 0 T oo many outputargument s0 ) ; / * 输入量必须是两个非复数 double 类型* / mrows0= mxGet M( prhs[ 0] ) ; ncols0= mxGetN( prhs[ 0] ) ;
if( ! mxIsDouble( prhs[ 0] ) | | mxIsComplex( prhs[ 0] ) | | ! ( mrows0= = 1& & ncols0= = 1) )
mexErrMsgT xt ( 0 Input s must be all noncomplex scalar double. 0 ) ; mrows1= mxGet M( prhs[ 1] ) ; ncols1= mxGetN( prhs[ 1] ) ;
if( ! mxIsDouble( prhs[ 1] ) | | mxIsComplex( prhs[ 1] ) | | ! ( mrows1= = 1& & ncols1= = 1) )
mexErrMsgT xt ( 0 Input s must be all noncomplex scalar double. 0 ) ; if( mrows0! = mrows1| | ncols0! = ncols1)
mexErrMsgT xt ( 0 Input s must be same dimen2 sion. 0 ) ; / * 为返回参数创建矩阵* /
plhs [ 0 ] = mxCreat eDoubleMatrix ( mrows0,ncols0, mxREAL) ; x= mxGet Pr( prhs[ 0] ) ; z= mxGetPr( prhs[ 1] ) ;
y= mxGetPr( plhs[ 0] ) ;
/ * 调用计算功能子程序 myplus( ) * / myplus( y, x, z) ; }
上面程序为一典型的 C 语言 MEX 文件, 程序由两部分构成: 一个计功能
18
学 士 学 位 论 文
BACHELOR ’S THESIS 子程序( myplus( ) 函数) 和两部分构成: 一个计算功能子程序( myplus( ) 函数) 和算功能子程序包含所有实际所需完成的功能、算法, 我们已有的或现编的 C/ C+ + 、FORTRAN 程序就被当做计算功能子程序使用, 它由入口子程序调用. 入口子程序是 MAT LAB 系统和外 部程序之间沟 通的桥梁, 主要用来完成两者之间的通信. 上面示例程序中, mexFunct ion( ) 函数有大量语句是用于检 查变量的数据类型等辅助性工作, 这是必要的, 因为 MATLAB 语言不像 C/ C+ + 等语言变量 使用前须声明, 对类型的检查可以避免许多错误的发生。[18]
下面简要的说明一下上面程序中用到的 MAT LAB AP I 函数, 它们在 mex. h 或 mat rix. h 中声明. mexF unction( ) , 入口子程序函数, 其格式如下:
void mexFunction( int nlhs, mxArray * plhs[ ] , int nrhs, const mxArray * prhs[ ] )
{
, , / / 一些必要的代码, 用来完成 MATLAB 系统与计算功能子程序之间的通信
}
其参数的含意为: nrhs 和 nlhs, 整型变量, 分别为调用 MEX 文件时输入、输出参数的个数. prhs、plhs, 指针数组, 其元素分别为指向输入、输出参数的指针. mexErrMsgT xt ( ) , 用于输出错误信息, 并返回到MATLAB 命令提示符下.
mxGetM( ) 和 mxGetN ( ) , 获得矩阵的行 数和列mxGetM( ) 和 mxGetN ( ) , 获得矩阵的行 数和列mxGetM( prhs 0] ) 的作用为: 得到第一个输入实参的行数, 并赋值给整型变量 mrows0.
mxIsDouble( ) 、mxIsComplex( ) , 判断矩阵是否为双精度型、复数型. 输入参数 为阵指针, 返回 值为BOOL 值.
mxCreat eDoubleMatrix( int m, int n, mxComplex2it y complexFlag) , 创建一个未赋值双精度矩阵, m,n 为创建矩阵的行、列数, complexFlag 为标识是实数还是复数. 该函数返回所创建 矩阵的指针。
mxGetP r( ) 获得矩阵实数部分的指针, 输入参数为矩阵的指针, 回值为矩阵实部分的双精度指针。
MATLAB API 函数还包含其它许多接口函数, 分为 mx2函数和 mex2函数, 详细情况可查阅相关文献。
19
学 士 学 位 论 文
BACHELOR ’S THESIS MEX 源程序编写完成后, 还要经过编译后才能生成 dll 文件, 供MATLAB 或其它程序调用, 编译前要对 MATLAB 进行编译器的配置.
4.2 编译器的配置
编译器的配置是通过MATLAB的配置文件( mexopts. bat ) 进行的, 其具体过程为: 在 MATLAB命令窗口下键入: mex2steup , 随后系统弹出一个DOS窗口, 按照提示一步步选择完成即可. 该命令可带许多参数, 可针对不同的操作系统进行多种配置。[4][16]
4.3 C
语言MEX文件的编译
编译方法很简单, 直接在 MATLAB 命令提示符下键入: mex filename, 其中 filename 为需编译的源程序名. 如果提示有错误信息, 需查错, 修改源程序、调试. 直到没有错误信息提示. 编译通过生成的可执行的 dll 文件, 可在 MATLAB 命令提示符下或 其它程序中调用.
4.4 举例说明C的 MEX源程序的编写和调用过程
首先看一个最简单的例子:
# include “mex. h”/ * 必须包含的头文件* / void Mul( double * x, double * y, double * z) {
* z = ( * x) * ( * y) ; }/ * 函数的功能是实现两个数的相乘* / void mexFunction( int nlhs, mxArray * plhs[ ] , int nrhs, const mxArray * prhs[ ] ) {
double * x, * y, * z;
20