VS2008与MATLAB R2009b混合编程环境配置
一,VS2008中的函数调用matlab的写好的函数
1.Matlab生成DLL
1.1编译器的安装
实验环境:
XP 32位机
MATLAB R2009b(安装路径:
D:Program Files/MATLABR2009b)
VS2008中文版(安装路径:
D:Program Files/Microsoft Visual Studio 9.0)
为了能够让 VC
调用 Matlab 程序,我们可以采用将 Matlab程序包装成动态链接文件 DLL
的形式,然后让 VC调用动态链接文件,因此在 Matlab
中,我们需要设置一下 Matlab的编译库,在 Matlab
主窗口中键入如下代码
1.安装设置
matlab编译器:
在matlab中先安装编译器,我在第一次安装的时候一路y下来,只有一个matlab的编译器compiler,这时就要选择N(需要添加VS2008的路径),按照以下步骤操作
>> mbuild -setup
Please choose your compiler for building standalone MATLAB applications:
Would you like mbuild to locate installed compilers [y]/n?n
Select a compiler:
[1] Lcc-win32 C 2.4.1
[2] Microsoft Visual C++ 6.0
[3] Microsoft Visual C++ .NET 2003
[4] Microsoft Visual C++ 2005 SP1
[5] Microsoft Visual C++ 2008 Express
[6] Microsoft Visual C++ 2008 SP1
[0] None
Compiler: 6
The default location for Microsoft Visual C++ 2008 SP1 compilers is C:Program FilesMicrosoft Visual Studio 9.0,
but that directory does not exist on this machine.
Use C:Program FilesMicrosoft Visual Studio 9.0 anyway [y]/n?n
Please enter the location of your compiler: [C:Program FilesMicrosoft Visual Studio 9.0] D:Program Files/Microsoft Visual Studio 9.0
(红 {MOD}部分换成你的vs所安装的地址)
Please verify your choices:
Compiler: Microsoft Visual C++ 2008 SP1
Location: D:Program Files/Microsoft Visual Studio 9.0
Are these correct [y]/n? y
2
>> mex -setup
操作与前面类似
1.2 DLL的生成
MyFunc.m放在工作区,具体的代码如下
function b = MyFunc(a)
b = a.*a;
将该m文件生成cpp文件使用mcc命令
mcc -W cpplib:MyFunc -T link:lib MyFunc.m –C
(其中 cpplib:后面的是需要生成文件的文件名,是自己取的, link:lib后面的 MyFunc.m
是转换为 DLL的 M
文件的文件名。 -W/-T/-C是参数,具体含义可以通过 mcc –help
命令查看,注意参数的大小写。)
运行完命令在工作区生成如下一系列文件
2. VS调用DLL
2.1新建一个项目,并设置环境
新建一个win32
控制台应用程序,我取的名字是matlabFun.当然新建其他的项目类型也可以,我这只是个例子。接下来进行配置,在该项目的属性中进行了配置,只对该项目有效。若建新的项目需要重新配置。项目建好后将MyFunc.lib, MyFunc.h, MyFunc.dll, MyFunc.ctf四个文件拷贝到项目目录下。
1.选择
“工具
-选项
-项目和解决方案
-VC++目录
”,在
“显示以下内容目录
”里选择
“包含文件
”将
“D:Program
FilesMATLABR2010bexterninclude”添加进去,然后选择
“库文件
”将
“D:Program FilesMATLABR2010bexternlib”添加进去,其中
D:Program Files 是
Matlab 的安装目录,可根据实际情况进行修改。
2. 配置项目属性页
/配置属性
/C-C++/常规
/附加包含目录
"D:Program FilesMATLABR2009bexternlibwin32";"D:Program FilesMATLABR2009bexterninclude"
目属性页/配置属性/链接器/常规/附加库目录,请根据自己电脑上软件的安装位置对照设置,如下图所示:
后配置项目属性页/配置属性/链接器/输入/附加依赖性,填入libmyadd2.lib
mclmcrrt.lib mclmcr.lib ,如下图所示:
2.2编写VS主程序,调试运行
#include "stdafx.h"
#include
#include "mclmcr.h"
#include "MyFunc.h"
int _tmain(int argc, _TCHAR* argv[])
{
MyFuncInitialize();
double _x[5] = {1,2,3,4,5};
double _y[5];
mxArray* x = mxCreateDoubleMatrix(1, 5, mxREAL);
memcpy(mxGetPr(x), (void*)_x, sizeof(_x));
mxArray *input[1] = {x};
mxArray *output[1];
mlxMyFunc(1,output,1,input);
mxArray *y;
y = output[0];
memcpy(_y, mxGetPr(y), sizeof(_y));
MyFuncTerminate();
return 0;
}
MyFuncInitialize ,
MyFuncTerminate,
mlxMyFunc均可以在
MyFunc.h文件中找到具体的定义。
mlxMyFunc 函数原型为:
mlxMyFunc(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[]) nlhs代表输出参数个数,
plhs[]里面存放的是输出参数的指针,
nrhs代表输入参数个数,
prhs[]中存放的是输入参数的指针。上例中由于输入输出参数只有一个,因此在
plhs[0]中存放的就是
M文件中
b
的指针,
prhs[0]中存放的就是
M文件中
a
的指针。编译运行之后就可以在弹出的消息框中得到所要的结果。
将项目文件夹下生成的可执行文件复制出来,将 MyFunc.dll文件、MyFunc.ctf
文件和matlabFun.exe文件放在同一目录下便可脱离 VC++独立运行。如果需要在其他未装 Matlab的机器上运行,则还需要将“D:Program FilesMATLABR2010b oolboxcompilerdeploywin32”中的
MCRInstaller.exe复制出来,在未安装 Matlab
的电脑上运行此程序,才可使得刚刚生成的可执行文件顺利运行。
二,matlab中的函数调用的VS2008的函数
通过使用C/C++与Matlab混合编程,既可以享受到C代码快速执行的速度,又可以方便的使用Matlab众多的库函数和强大的绘图功能。让Matlab调用C函数是通过DLL文件实现的,而这个DLL的开发过程不仅仅可以使用Matlab自带的mex命令,还可以使用VC++开发环境,使用VC有很多好处,一是让我回到了原来熟悉的开发环境中,二能够使用更加标准的C++编译器,第三点也是最爽的,可以使用VC强大的调试功能。
方法一,不需要调试,直接用mex命令即可
与1.1中的设置编译器相同,在matlab窗口中输入命令
>> mex -setup
选择Microsoft Visual C++ 2008 SP1即可。
在VS中编写testadd.cpp文件,如下
#include "mex.h"
double add(double x,double y)
{
return(x + y);
}
void mexFunction(int nlhs,mxArray *plhs[],
int nrhs,const mxArray *prhs[])
{
double *a;
double b, c;
plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL);
a = mxGetPr(plhs[0]);
b = *(mxGetPr(prhs[0]));
c = *(mxGetPr(prhs[1]));
*a = add(b, c);
}
将matlab的执行路径调整到cpp目录下,执行命令
>>mex testadd.cpp
即可在相同的路径下方产生testadd.mexw32文件。然后在matlab窗口中输入函数的名称即可调用testadd的VS函数。
>>testadd(4,5)
>>ans=9
以上的方法仅能得到mexw32文件,不能实现VS和matlab的联调。
方法二,用DLL文件的方式生成mexw32,然后可以从VS中启动matlab调试。
1. 新建一个空的
dll程序
2. 为
matlab函数提供头文件和静态库的支持
在Include files中添加”…externinclude”和”…externincludewin32”,
在Library files中添加”…externlibwin32microsoft”。
在项目属性中,让链接器链接libmx.lib、libmat.lib和libmex.lib,如图:
添加Preprocessor Definitions中添加MATLAB_MEX_FILE的宏定义。
现在写一个dll程序就可以编译通过,生成项目的debug文件,如:
3. 利用
def文件导出
mexFunction函数
首先告诉编译器我使用了testadd.def文件,在链接器-输入-模块定义文件中填上testadd.def
再在工程目录中编写testadd.def的内容,(新建记事本,然后将*.txt改为testadd.def即可)
在该def文件中只需添加两句话:
LIBRARY testadd
EXPORTS mexFunction
最后,在链接器-常规-输出文件中将输出文件的后缀dll名改为mexw32
再次编译、生成,可以在生出目录mexw32文件。
4. 在
VS中启动调试时关联
matlab窗口设置
在调试-命令里添加Matlab的启动地址:”…inwin32MATLAB.exe”。如图:
在“工作目录”中添加testadd.mexw32文件所在的目录,如下图:
在VS程序中设定断点,启动VS调试,会弹出提示,点击“是”就行了。
Matlab窗口会自动启动,再在
MATLAB中输入要运行的函数命令即可实现联调状态:
返回到VS程序中,可以查看变量的值
最后在matlab中得到最终的运行结果
当然,最终使用的mexw32文件还应该是Release版本的,这样的话,上面谈的部分设置还需要在Release版本中重新来过。
至此,我发现只能在VS中启动matlab窗口,然后在matlab中输入调用C函数命令,才能进行联调。而从matlab中启动VS平台,进行调试的方法则目前还没有,可能是两大运营平台的合作问题吧。
三,混合编程中常用的函数
MEX文件的源文件实际上就是一个
C语言源文件,
MEX的源文件结构由两部分组成:入口子程序和功能子程序。
其中入口子程序函数名必须为mexFunction。其中nlhs (number of left-hand side)是输出参数的个数,nrhs(number of right-hand side)是输入参数的个数。prhs[]与plhs[]是指针数组变量,其元素为指向右变量与左变量的指针。在用户程序中可利用上述指针在C与MATLAB中相互传递数据。MEX函数库里的mexFunction()函数,相当于C语言中的main()函数。MEX源文件没有main(),而是以一个mexFunction()代替。
功能子程序用于完成一些特定的计算功能或硬件处理功能,由上述的入口子程序调用。如果必要,该程序可与入口子程序合二为一。
入口子程序起链接C子程序与MATLAB系统的作用,是实现MATLAB与C混合编程所必须的。格式为:
#include "mex.h"
double add(double x, double y)
{
return x+y;
}
void mexFunction(int nlhs, mxArray *plhs[],int nrhs,const mxArray *prhs[])
{
double a,b,*c;
a=mxGetScalar(prhs[0]);
b=mxGetScalar(prhs[1]);
plhs[0]=mxCreateDoubleMatrix(1,1,mxREAL);
c=mxGetPr(plhs[0]);
*c=add(a,b);
}
首先对文件内容进行简单说明:
其中nlhs (number of left-handside)是输出参数的个数,nrhs (number of right-hand side)是输入参数的个数。例如对于c=add(a,b),有nlhs=1,hrhs=2。
plhs[]与
prhs[]都是指针数组,也就是说它是个数组,每个元素都是一个指针,这些指针指向的东东的类型是
mxArray。那什么是
mxArray呢?可以把他理解
MATLAB中的矩阵,因为
MATLAB中所有数据都是以矩阵的形式保存的。
先讲prhs[],就是输入的参数,prhs[0]指向a,prhs[1]指向b,但是注意不能用*(prhs[0])得到a的值。因为
prhs[0]指向的东西的类型是mxArray(参数列表里看出),想把它的值以我们常用的数值形式赋给一个标量(Scalar),得使用 mxGetScalar()函数转化一下:
double a, b;
a = mxGetScalar(prhs[0]);
b = mxGetScalar(prhs[1]);
plhs对应的输出的内容。
plhs[0]这个指针指向输出的第一个参数,就是
c=add(a, b)中的
c了。记住这个
c应该是以
mxArray的类型出现的,为了得到
mxArray类型的输出量,要使用
mxCreateDoubleMatrix()函数,它创建一个指向
mxArray类型的指针。
plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL);
参数(1, 1, mxREAL)定义了对应c的尺寸类型,MATLAB中c是以1×1的实数矩阵形式报保存的。
而使用mxGetPr()函数可以得到plhs[0]指向的mxArray的第一个double类型的指针。
double *c;
c = mxGetPr(plhs[0]);
最后调用add()函数
*c=add(a,b);
在Matlab命令窗口输入命令
mex MyMEXFun.c
可以看到在当前目录生成新文件MyMEXFun.mexw32。在命令窗口中输入c=MyMEXFun(3,4)命令,可得到c=7。
使用mex时的注意事项:
1.MATLAB调用
mex接口时,将参数个数及参数指针传入接口子程序,由接口子程序完成指针和调用变量的赋值、输出数据的内存空间分配,接口子程序再将参数指针或经过赋值的变量作为参数传递给
C的计算子程序,完成调用过程。调用时应注意指针所指对象的正确性,为处理正确最好做相应的强制类型转换。
2.mex并不便于调试,因此应在
C的
IDE中用测试集调试后再放入
mex文件中。
3.MATLAB中指向二维及高维数组的指针递增方式是按行递增的,而
C中是按列递增的,因此计算
index时要注意位置。
MATLAB矩阵数据的存储顺序是”从上到下,从左到右”。
MATLAB的指标从
1开始,
C的指标从
0开始。
为了mex的正确执行,也是良好编程习惯的要求,需要对输入参数和输出参数进行个数和类型的检查,常用的mex库函数有:
mxGetClassID //获得指针所指变量类型
mxIsNumeric, mxIsCell等,检查指针所指变量是否为符合某种要求的变量类型。更多可查阅帮助。
参数检查过程中可使用mexErrMsgTxt输出错误信息。
mxGetM, mxGetN,获得矩阵的行数和列数
mxGetDimensions,获得矩阵维数
mxGetPr,
mxGetPi,获得矩阵实数部分、虚数部分的指针
mxGetString, 获得字符串内容
mxGetElementSize, 获得存储矩阵元素所需要的字节数
mxCalloc,内存分配。用
mxCalloc不用
calloc和
malloc,因为
mxCalloc会自动释放内存,不需要手动
free了。
mxCreateString, 创建
1*N的字符串矩阵
mxCreateDoubleMatrix,
创建
2维双精度浮点矩阵,可以是实数
(mxREAL)或者复数
(mxCOMPLEX)
mxCreateStructArray,
创建
N维结构体矩阵
mxCreateCellMatrix, 创建二维单元矩阵
mxCreateNumericArray,创建
n维数值矩阵
mexPrintf, 重新封装的
printf
mxSetFiled, 设置结构体矩阵的域
mxSetCell, 设置单元矩阵的单元值
mxSetPr, 设置矩阵实数值
mxSetPi, 设置矩阵虚数值
mxCallMATLAB,调用
MATLAB中其他内建函数、自定义
M文件、
mex文件。