C语言环境中调用Matlab程序指南
甄梓宁
znzhen@gmail
Matlab在计算方面功能强大、编写简单,但是要运行Matlab程序必须装有Matlab并且用户界面也不够完善,因此除了计算的其他部分采用C等更规范完备的语言进行编写是较好的选择。本文就对如何在C程序中调用Matlab程序作说明。
在C程序中调用Matlab程序有两大类方法。第一种是调用Matlab引擎,第二种是将m文件打包成dll文件在C语言环境下调用。前者虽然易于实现,可以实时监控程序的运行,但是独立性差,需要安装完整版Matlab,且每次调用都会启动进程;后者则实现复杂,调试麻烦,但只需安装MCR(Matlab Component Runtime),耗费资源较少。关于MCR,请见第四章的说明。至于两种方法需要在C环境中如何配置请见第五章。
而反过来若要在Matlab下调用C程序则一般使用Matlab自带的mex工具,在此不作介绍。
一、调用Matlab引擎
调用Matlab引擎可以在WIN32、MFC中使用,它的原理实际上相当于打开一个精简版的Matlab然后往里面输命令。下面是调用Matlab中的加法程序add.m的例子。
先在Matlab的work目录下创建add.m文件并编写程序如下:
function s = add (a, b)
s = a+b;
在C程序中,首先打开精简版的Matlab:(所需头文件,引用库等见第五章)
Engine *ep = engOpen (NULL);
c语言编译器怎么安装编译运行后,会自动打开一个命令行监控窗口,输入pwd就可以看到当前的工作目录,于是需要先将工作目录转换至存放add.m的目录:
engEvalString (ep, ”cd ..\\..\\work”);
engEvalString是往Matlab里输命令的函数,显然我们的目标是成功运行:
engEvalString (ep, ”s=add(a,b)”);
当然,目前Matlab中并没有a和b两个变量,因此需要在C中初始化这两个变量并转换成Matlab基本变量类型mxArray,才能将它们输入到Matlab中。关于mxArray,在第三章会有详细说明。下面是对a=1,b=2的转换过程:
double aval=1, bval=2;
mxArray *a=mxCreateDoubleMatrix(1,1,mxREAL);
mxArray *b=mxCreateDoubleMatrix(1,1,mxREAL);
mxSetPr(a,&aval);
mxSetPr(b,&bval);
于是可以往Matlab里输入了:(双引号内是在Matlab里的变量名称)
engPutVariable(ep,"a",a);
engPutVariable(ep,"b",b);
运行add.m:
engEvalString (ep, ”s=add(a,b)”);
编译运行后可以在监控窗口中查看s,确认是3无误。接下来就是怎样把s从Matlab读入C中的问题了,也很方便:
mxArray *s=engGetVariable(ep,"s");
显示一下:
printf("s=%f",*mxGetPr(s));
最后不要忘记关闭Matlab:
engClose(ep);
用到的几个mxArray也需要释放,在此不述,具体请见第三章。
到此,调用Matlab引擎的全过程就结束了。不管m文件的函数形式有多复杂,都万变不离其宗,改变的只有变量与mxArray相互转换那一部分,具体请见第三章。
另外,Matlab还提供了将监控窗口中的显示存入某buffer的函数。可以如下设置:
char buffer[1000];
engOutputBuffer(ep,buffer,1000);
这样,所有显示都会存入buffer中,这对调试很有帮助。如果想取消这个功能,则:engOutputBuffer(ep,NULL,0);
最后还可以将监控窗口关闭或重新打开:
engSetVisible(ep,false);
engSetVisible(ep,true);
以上便是调用Matlab引擎的全部内容。这种方法步骤简单,调试也方便,所以在一般场合下使用已经足够好了。
二、打包m文件至dll
打包m文件至dll相对于调用Matlab引擎,唯一也是最重要的一点好处是便于发布。
在一台没有安装Matlab的电脑中,利用最少的资源运行Matlab程序只有这种方法。
该方法根据dll的不同又可分为两类:一是打包成COM或.NET组件的dll,二是传统的dll。前者除了在WIN32、MFC中还可在.NET中运行。本文仅介绍较为简单的打包成传统dll的方法。
下面这个例子将自己编写的加法程序add.m及乘法程序multi.m打包至calc.dll并在C 程序中调用。add.m如第一章所示,multi.m如下所示。
function s = multi( a, b )
s = a*b;
第一步,设置Matlab中使用的C语言编译器:
mbuild –setup
弹出如下提示:
Please choose your compiler for building standalone MATLAB applications:
Would you like mbuild to locate installed compilers [y]/n?
选y的话会列出Matlab默认的几个编译器及其默认路径。如果没有完全符合的话则重来选n,就会出现更
多的选择:
Select a compiler:
[1] Borland C++Builder version 6.0
[2] Borland C++Builder version 5.0
[3] Borland C/C++ (free command line tools) version 5.5
[4] Lcc C version 2.4.1
[5] Microsoft Visual C/C++ version 8.0
[6] Microsoft Visual C/C++ version 7.1
[7] Microsoft Visual C/C++ version 6.0
[0] None
Compiler:
根据个人喜好输入相应编译器序号后,就会要求确认路径。若没有,则显示如下:
The default location for xxxxxxx compilers is C:\xxxxxxx, but that directory does not exist on this machine.
Use C:\xxxxxxx anyway [y]/n?
选n输入其应该在的路径即可。
第二步,在Matlab中将add.m及multi.m文件编译为calc.dll:
mcc -W lib:calc -T link:lib add.m multi.m
第一个选项-W的格式是“dll类型:生成的dll名称”,dll类型可以是C下的“lib”,C++下的“cpplib”,COM下的“com”以及.NET下的“dotnet”。
第二个选项-T是生成类型,可以是“link:exe”生成exe文件,以及我们所用的“link:lib”
生成dll文件。
正常运行后会生成一排文件,其中有用的是以下这几个:
mccExcludedFiles.log:编译中被排斥的项目列表。
calc.h和calc.lib:C程序编写时需要。
calc.dll和f:C程序执行时需要。
在mccExcludedFiles.log中有两类被排斥的项目。一类是Excluded by M-file compilabilty rules,这类排斥是由于m文件使用的Matlab Toolbox函数中调用了被排斥的函数导致的。一种解决办法是将需要的Toolbox函数进行简化,尽量只使用最基本的Matlab函数。
另一类是Excluded because they ship with the MCR,这类排斥没有影响,无视即可。
第三步,在C程序中调用calc.dll中的函数:
首先将calc.h、calc.lib、calc.dll、f四个文件拷贝至C程序同一目录中,并在程序中包含calc.h以及在链接的附加依赖项中添加calc.lib。
随后,可以在calc.件中到我们需要使用的几个函数:
calcInitialize():calc.dll初始化程序。
calcTerminate():关闭calc.dll
mlfAdd(int nargout, mxArray** s, mxArray* a, mxArray* b):调用calc.dll中的加法程序。
mlfMulti(int nargout, mxArray** s, mxArray* a, mxArray* b):调用calc.dll中的乘法程序。
另外,初始化的时候还可以改用calcInitializeWithHandlers设置消息处理函数,这在本章最后详细说明。下面是调用加法程序的C程序:(所需头文件,引用库等见第五章)
//calc.dll初始化
calcInitialize();
//a=1, b=2转换为mxArray格式
double aval=1, bval=2;
mxArray *a=mxCreateDoubleMatrix(1,1,mxREAL);
mxArray *b=mxCreateDoubleMatrix(1,1,mxREAL);
mxSetPr(a,&aval);
mxSetPr(b,&bval);
//调用calc.dll中的加法程序
mxArray *s=NULL;
mlfAdd(1,&s,a,b);
//显示结果
printf("s=%f",*mxGetPr(s));
//释放mxArray
mxDestroyArray(a);
mxDestroyArray(b);
mxDestroyArray(s);
//关闭calc.dll
calcTerminate();
整个调用过程跟调用Matlab引擎非常类似,在程序开头运行dll初始化程序很重要,在编程时容易忽略掉这一步导致出错。另外,在调用加法的函数mlfAdd中,第一个参量是输出的个数,而输出都需要取mxArray*的地址,也就是mxArray**。关于mxArray的结构,会在第三章详细说明。
以上便是m文件打包至dll并调用的全过程。
接下来,介绍一下消息处理函数。前面已经提到,采用打包dll方法调用Matlab函数会导致调试麻烦,因此一个好的消息处理函数是必不可少的。而前面采用的dll初始化程序calcInitialize()是不使用消息处理函数的,下面我们将使用calcInitializeWithHandlers函数设置消息处理函数。
calcInitializeWithHandlers函数有两个输入参量:一个是error_handler,一个是print_ handler。前者是由Matlab中error函数触发的,说明调用函数彻底失败了;后者由除了前者以外的一切显示输出触发。这两个函数的参量列表是由mclOutputHandlerFcn定义的,格式如下:
typedef int (*mclOutputHandlerFcn)(const char *s)
一般,print_handler可以根据需要编写,而error_handler则最好弹出对话框提示错误。参考程序如下:(需要注意的是消息处理函数必须为静态的)
static int error_handler(const char *msg)
{
printf("Error: %s\n", msg);
return 0;
}

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。