众所周知,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代码。
其中的参数-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。