VC++和Matlab混合编程

以下文章转载自http://www.cnblogs.com/mfryf/archive/2012/02/16/2354295.html


一、前言

        Matlab是由Mathworks公 司推出的一种应用软件,最早用于线性代数的教学,由于其丰富的矩阵运算,强大的扩展能力和可靠性,已经被广泛用于信号处理,系统辨识,仿真,多变量控制, 最优控制,模糊控制,数学工具,神经网络,它的工具箱内容涉及信号处理,自动控制,图像处理,经济,数学,化学等不同领域。同时,MathWorks公司从创立至今始终追踪各领域的最新进展,这无疑是最明智,最富远见的举措。对广大用户来说,无疑提供了成功的机会。对于各种理论方案研究来说,Matlab无疑有它的先天优势,其强大的数据处理能力和丰富的工具箱,使得它的编程极为简单,可以极大地缩短应用程序开发周期,提高编程效率和缩短理论方案研制周期。总之,对于纯理论方案来说,Matlab语言是优势多多。但由于Matlab是为了方便用户而编制的,采用的是类似Basic一样解释型机制的语言。所以Matlab语言执行效率很低,只有C语言的十分之一,对于对实时性或速度要求较高的场合来说,Matlab就不太适应了。Matlab是一种高级语言,对底层硬件的控制能力很差,所以对于半实物仿真和偏工程化的产品来说,Matlab并不是一个很好的语言。对于发布软件公司来说,也希望发布的是一个可执行应用软件,而不是一个只是Matlab原代码的产品。所以把Matlab语言转换成可执行文件,具有较强的工程实用价值。Microsoft的Visual C++面世以来就受到了风靡全球,其强大硬件控制能力和系统集成功能使无数程序员对它一见倾心。Matlab在它的5.1 版本后,就逐渐增加了对C的支持,本文就对此问题作一简单探讨,欢迎大家批评指正。

二、Matlab与C语言混合编程方法简介。

        Matlab与C语言混合编程有四种方法

        A.采用Matlab与C的接口规范来编程。

        Matlab与C语言的接口采用称为MEX的动态链接库方式进行。按MEX接口规范编写的C原程序经过编译可生成Matlab动态链接子程序,它十分类似于Matlab的内建函数,可有Matlab直接调用。采用此规范可实现对Matlab原代码的加密。

        B.用Matlab引擎来编程Matlab引擎采用的是客户机/服务器(Client/Server)的计算方式。

        所谓客户机/服务器计算,就是把应用处理负载分布到客户机和服务器上的工作模式。客户机与服务器即可以存在于同一台计算机,也可以通过网络共享信息。一般情况下,客户机是运行软件的前端PC机,并且知道如何与服务器通讯;服务器于此对应,是接受信息,并采用相应行动的机器。由于客户机于服务器共同承担处理负载,可使系统性能得到极大提高。在一个实际应用中,可用VC活其它C,C++语言作为前端客户机,它向Matlab引擎发送命令和数据信息,可从Matlab引擎获得计算结果。

        C. 用Matlab下的.m文件转化为VC可调用动态链接库(DLL)。下面详述。

        D.直接用C编程,通过对Matlab的数学库函数的调用实现Matlab语言的一般功能,下面详述。

由于采用方法A和方法B都脱离不了Matlab 运行环境,这里不作详细介绍,下文主要介绍方法C和方法D。

三、 如何把Matlab下的.m文件转化为VC 可调用的动态链接库

3.1    VC下的DLL简介

        在软件的开发过程中,DLL已成为常见的编程单元。DLL虽然是可执行文件,但它不能独立运行,只能被其它应用程序调用。在VC6.0中,MFC支持三种新式DLL 

        a.通常形式的静态DLL

        b.通常形式的动态MFC的DLL

        c.扩展DLL(动态链接MFC)

        本文采用通常形式的静态DLL开发和使用DLL,应注意以下几点。

        a.DLL头文件(.H)。DLL头文件是指DLL中说明输出的类和符号(Symbols),如函数原型和数据结构的.H文件。一方面,它是类和符号原型说明文件,另一方面,当在其它应用程序中调用DLL时,要将该文件包含应用程序中的源文件中。

        b.DLL的引入库文件(.LIB)。引入库文件是DLL在编译,链接成功后的生成的文件。它的主要作用是:当其它应用程序编译调用DLL时,要将该文件引入应用程序。

        c.DLL文件(.DLL)。DLL是应用程序调用DLL运行时,真正可执行的代码文件。 在开发一个DLL 应用程序时,要用到这三个文件。

3.2     Matlab下的Mcc简介

        MCC同样是Mathworks公司出品的一种应用软件。可在/matlab/bin下找到它,它的作用是把.m文件转换成C/C++文件器。Mcc(版本2.0)用法格式是Mcc [ -选项] fun [fun2 …],如果指定的fun是.m文件,则每个文件都会被转换成C/C++文件,如指定fun的是.c文件,这些c和相关的c文件将被传递给mex和mbuild 程序编译。Mcc的用法很复杂,具体使用可参见MCC2.0 Online Help.

3.3    用.m文件创建一个VC可调用的DLL文件示例

3.31    编辑一个子调用的.m文件

        基于说明问题起见,用Matlab的edit编了一个简单的myfunc.m文件,程序如下图所示:

 fuction y=myfunct(x,b)定义一子调用,程序中其中x为输入变量,b为控制选项,b=1时以角度值输入,b=其它时,以弧度值输入,程序通过插值方法求得x的正弦值返回给y。

3.32    Matlab编译前的准备工作。

        a. 对Matlab编译环境进行设置在Matlab环境中运行mex -setup,按屏幕提示要求选择编译器类型,位置等有关信息。如下图所示:

        b.在Matlab环境中运行mbuild -setup,设置方法与上面基本相同,这儿就不详述了,mcc和mbuild的设置结果分别保存在mexopts.bat和compopts.bat文件中。

3.33     用mcc将myfunc.m转换为matlab可调用的DLL

        在Matlab环境中运行mcc -t -h -L C -W lib:ppp -T link:lib myfunc.m

        下面分别介绍各选项的意义:

        -t 把M代码转换成目标语言。

        -h 把辅助编译器选项打开,打开此选项意味着可以链入除Matlab已有的函数外,还可以链入作者自编的子函数。

        -W lib:ppp 表示生成DLL所需的ppp.h ppp.lib ppp.dll

        -T link:lib 表示编译生成的目标(Target)文件类型为DLL

        编译完成后,将生成如下一些文件ppp.exp ppp.lib myfunc.c ppp.c ppp.exports myfunc.h ppp.dll ppp.h, 其中有用的文件有三个,分别是ppp.h,ppp.lib,ppp.dll,它们将会被添加到VC程序中去。

3.34     用MFC编译一个VC++6.0可执行文件 

        1.由于dll不能独立运行,所以要用VC6.0创建一个EXE可执行程序。在VC6.0中创建一个基于对话框的MFC工程,名为mytest,具体过程参见一般的VC教程。在本例中mytest工程路径为e:\mat2c\mytest

        2.对VC编程环境进行设置。

选择VC编译器主菜单下Tools->options->directories,选择Show Directories for列表框,分别把Matlab的包含文件路径(如c:\matlab\ertern\include),库文件(如C:\matlab\extern\lib)路径添加到VC路径中去。

        3.把ppp.h,ppp.lib,ppp.dll三个复制到e:\mat2c\mytest目录下,以便Vc调用DLL时能找到这三个文件。对对话框IDD_MYTEST_DIALOG资源进行编辑,如下图所示 “ 请输入数值“,”输出正弦值“为两个静态文本框,两个Edit为编辑框,分别用来接受输入数值和输出数值。对应的变量为双精度类型的m_din, 和m_dout.。角度“,”弧度“选项表示输入数值单位制,对应的变量为m_select。“计算“按钮则启动计算功能,定义它的ID为ID_ON_ON_CALCULATE,相应的消息处理函数为OnOnCalculate(); 

        要使VC能调用DLL,还必须对VC进行以下操作。

        (1)引入头文件和库文件

        在mytestdlg.cpp的头部加入一行:#include “ppp.h”;

在project>settings->link下的object/libray modules下加入ppp.lib libmx.lib libmat.lib libmatlb.lib libmmfile.lib目的是让VC能调用ppp.dll,引入libmx.lib libmat.lib libmatlb.lib 和libmmfile.lib的目的是让VC能调用matlab的数学库函数和一些功能性函数编译VC与matlab的代码接口,和作者直接用C写的一些代码。

        (2)对ppp.h做一点改动。

        在#include “matlab.h”语句之后,加入-行

        extern “C”{

        在最后一行#endif之前加入一行

        

        改动后的ppp.h文件内容如下:

#ifndef MLF_V2

#define MLF_V2 1

#endif 

#ifndef __ppp_h

#define __ppp_h 1 

#include "matlab.h"

extern "C"{

extern mxArray * mlfMyfunc(mxArray * x, mxArray * b);

extern void mlxMyfunc(int nlhs, mxArray * plhs[], int nrhs, mxArray * prhs[]);

extern void pppInitialize(void);

extern void pppTerminate(void);

}#endif。

        (3)对VC与Matlab接口进行编程。

对“计算”按钮消息处理函数编程如下

        void CMytestDlg::OnOnCalculate()

        

        // TODO: Add your control notification handler code here 

        UpdateData(TRUE); 

pppInitialize(); 

static double a[1] = { 0.0 }; 

static double b[1]= { 0.0 }; 

a[0]=m_din; b[0]=m_select+1; 

mxArray * A = mclGetUninitializedArray(); 

mxArray * B = mclGetUninitializedArray();

 mxArray * C = mclGetUninitializedArray(); 

mlfAssign(&A, mlfDoubleMatrix(1, 1, a, NULL)); 

mlfAssign(&B, mlfDoubleMatrix(1, 1, b, NULL)); 

mlfAssign(&C, mlfMyfunc(A, B)); 

double * md=mxGetPr(C); 

m_dout=md[0];mxDestroyArray(A); 

mxDestroyArray(B); 

mxDestroyArray(C); 

pppTerminate(); 

UpdateData(FALSE);

        }

为了使读者有一个更深入的了解。对以上关键性代码加以说明。

        UpdateData(TRUE)表示从屏幕接收数据,

        a[0]=m_din;表示a[0]存放m_din,即输入的待计算数值, 

        b[0]=m_select+1;表示 b[0]“角度“,”弧度“的选择值。

由于Matlab的计算基本单位是矩阵,而VC支持的基本数据类型是int,double等,所以要编写Matlab与vc之间的接口代码。如本例中C=myfunc(A,B)的函数,它编译成动态链接库后C形式代码为

        mlfAssign(&C, mlfMyfunc(A, B))。

要使Vc能调用它,必须首先创建三个mxArray *型指针变量 mxArray * A, mxArray * B, mxArray *C指向A,B,C矩阵(mxArray * A = mclGetUninitializedArray(); 

mxArray *B= ……),

由于A,B是输入变量,故使用 

        mlfAssign(&A, mlfDoubleMatrix(1, 1, a, NULL)),

        mlfAssign(&B, mlfDoubleMatrix(1, 1, b, NULL))

语句使得A,B矩阵中的元素与 double a[1],static double b[1]内容保持相同。

再使用mlfAssign(&C, mlfMyfunc(A, B))语句调用ppp.dll中的mlfMyfunc函数计算并返回结果到C中.double * md=mxGetPr(C)语句作用是取得返回doulbe *指针,这样m_dout=md[0]使得m_dout取得的内容就是C矩阵中的第一个元素(即在Matlab语言中为C(1) 的元素,在C/C++语言中,0指示的是数组的第一个元素).这样一个DLL 调用就完成了,最终通过UpdateData(FALSE)语句把运算结果显示出来了。以上程序中的某些函数用法中参见Matlab中的C Math帮助文件。

        (4)作完以上工作后,DLL就已被成功链入VC,再经VC编译器编译链接即可生成可执行文件,运行程序,在对话框中输入60,选择角度选项,按计算按钮即可得到结果。

 四.直接用C编程

        接用C编程也是可以的,它是通过对Matlab的数学库函数的调用来实现的,如果能用Matlab实现的语句,就用不着非得用C直接编程因为直接用C编程与把.m文件通过mcc转换成的C代码是一样的的如要实现Matlab中的以下三行功能:A=[1 2 3 4];

B=[4 3 2 1];

C=A+B;

自己直接用C要这样写 

static double a[4] = { 1.0, 2.0, 3.0, 4.0 };

static double b[4] = { 4.0, 3.0, 2.0, 1.0 };

 mxArray * A = mclGetUninitializedArray(); 

mxArray * B = mclGetUninitializedArray(); 

mxArray * C = mclGetUninitializedArray(); 

mlfAssign(&A, mlfDoubleMatrix(1, 4, a, NULL)); 

mlfAssign(&B, mlfDoubleMatrix(1, 4, b, NULL)); 

mlfAssign(&C, mlfPlus(A, B));

而如果用mcc把上面三行转化为C代码以后为:

static double __Array0_r[4] = { 1.0, 2.0, 3.0, 4.0 };

static double __Array1_r[4] = { 4.0, 3.0, 2.0, 1.0 }; 

mxArray * A = mclGetUninitializedArray(); 

mxArray * B = mclGetUninitializedArray(); 

mxArray * C = mclGetUninitializedArray(); 

mlfAssign(&A, mlfDoubleMatrix(1, 4, __Array0_r, NULL));

mlfAssign(&B, mlfDoubleMatrix(1, 4, __Array1_r, NULL)); 

mlfAssign(&C, mlfPlus(A, B)); 

它们实质上是一样的,直接用C编程不如先写.m代码,再用mcc工具转换。 

对Matlab与VC编译器环境的配置工作与上面第3节介绍的一样。

注意:libmx.lib libmatlb.lib libmmfile.lib libmat.lib 文件并不是Matlab自带的,Matlab只提供了libmx.dll libmatlb.dll libmmfile.dll libmat.dll 用户需要自己编译,

        在VC有两种方式实现(推荐方式(2))

        (1)VC集成编译环境中打开 matlab\extern\examples\cppmath\msvc 下的工程文件msvc42.mak,

选project->settings->C/C++->code generation 为Debug Multithread Dll选项,Build即可。

        (2)把VC的bin目录下的vcvars32.bat拷贝的C盘根目录下运行msconfig将vcars32.bat添加的Auoexec.bat中去。重新启动计算机。回到MS_DOS方式下在matlab\extern\include运行lib /def:libmat.def /machine:ix86 /out:libeng.liblib /def:libmatlb.def /machine:ix86 /out:libmatlab.liblib /def:libmmfile.def /machine:ix86 /out:libmmfile.liblib /def:libmx.def /machine:ix86 /out:libmx.lib 

        不论是方式(1)还是(2),生成的libmx.lib libmatlb.lib libmmfile.lib libmat.lib文件都要拷贝到c:\matlab\extern\lib(也就是添加到VC的编译路径中去)。

        本文中的文件路径可能跟读者计算机中的路径有所不同,请参照修改。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值