将Matlab代码转换为DLL进行C_混合编程

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

将 M a t l a b 代码转换为 D LL 进行 C+ + 混合编程
王学斌
摘 要: 介绍了将 Matlab 代码转换为 DLL 进行 C++混合编程的步骤、 环境设置、 Driver 代码编写 以及发布的技巧, 使得 C++程序员可以在自己开发的程序中利用 Matlab 强大的算法设计功能, 快 速实现符合自己需要的复杂算法。

关键词: Matlab ; DLL ; MCC ; C++
multiplymatrix.m
function m = multiplymatrix(a1, a2) m = a1*a2;
eigmatrix.m
function e = eigmatrix(a1) e = eig(a1);
引言
1 Matlab 是一个数学计算、 算法设计、 验证的高级工具, 拥 有丰富的数学、 统计、 绘图函数库 , 其 m 代 码 简 单 易 学 、 执 行效率高, 是进行算法设计与验证 的 最 优 工 具 。

但 是 将 m 代
码引入自己的程序却需要有一些专业的知识来进行指导。

Matlab 拥有一个自己的代码编译器 mcc , 利用 mcc 可以将 m 代 码 转换为独立执行程序 、 COM 组 件 或 者 DLL 库 。

对 于 C++程序员来说, 最好的方法是将 m 代码转换为 DLL 库, 然后 引入自己的程 序 , 使 得 在 Matlab 中设计的算法可以直接变为
自己的 C++程序。

在下一步中, 将这 3 个文件转换到一个 dll 中。

4 生成 DLL
Matlab 的代码编译器 mcc 可以创建基于 C 语言的 dll 以及
基 于 C++ 语 言 的 dll 。

为 了 简 单 起 见 , 仅 介 绍 C++ 的 dll 创 建
方法。

将 以 上 3 个 m 文件拷贝到一个目录中 , 并 在 Matlab 中将工作目录设为该目录 , 然 后 在 Matlab 控 制 台 中 输 入 以 下命 令 :
2 转换过程
整个过程可以分为以下 4 步: (1) 编写 m 代码。

(2) 利用 mcc 将 m 代码编译为 dll 库。

(3) 在 cpp 程序中引入 dll 库, 并编写 Driver 代码 ,
m 文件中提供的函数。

(4) 制作发布程序。

mcc -W cpplib:libmatrixp -T link:lib addmatrix.m multiply - matrix.m eigmatrix.m
成功运行后生成以下文件:
libmatrixp.h , 包含函数入口的头文件。

libmatrixp.lib , Lib 库文件。

libmatrixp.dll , DLL 文件。

libmatrixp.ct f , 支持 dll 运行的 CTF 文件 (必须放入 exe 文
件的搜索路径中)。

以上 4 个文件是下一个步骤中需要的, 另外还生成了一些
过 程 文 件 。

注 意 dll 库 的 名 称 由 mcc 的 一 个 参 数 指 定 , 即 cp-
plib:libmatrixp , 其他参数都是不变的:
调 用
3 编写 m 代码
m 文件分为两种: 脚本文件和函数文件。

脚本文件没有输 入输出参数, 由 一 系 列 Matlab 变量和函数组成 , 可 以 直 接 执 行; 而函数文件则类似于 C 语言中的函数, 拥有输入输出参数 以及返回值。

只有函数文件可以被转换为 dll , 若 想 转 换 脚 本
文件, 则将这个脚本文件加一个函数名就可以了。

在 C++程序中引入 DLL
环境设置
虽然 Matlab 提供了一个 mbuild 工具可以很方 便 地 编 译 链
5
5.1 事 例 中 准 备 了 三 个 m 文 件 , 分 别 是 addmatrix.m 、 multi-
plymatrix.m 和 eigmatrix.m , 其功能分别是计算矩阵加法、 矩阵
乘法和矩阵的特征值, 代码如下:
接生成的 dll 和自己的 cpp 代码, 但是考虑到大部分人都是使 用 IDE 环境, 因此这里只描述了如何使用 MSVC 工具来编译链 接 dll 。

开发环境如下:
addmatrix.m
function a = add matrix(a1, a2) a = a1 + a2;
(1) (2) (3) Windows XP 。

Matlab7.1。

MSVC2008。

首先在 VC 的 include 路径中加入 (%MATLAB_H OME %代 表 Matlab 的安装目录):
然后在 VC 的 Lib 路径中加入:
5.2 编写 Driver 代码
要调用 Dll 中的函数, 有一套特定结构的 Driver 代码。

首 先创建一个 C++工程, 名字为 Matlab71Exam , 在主文件中加入 如下代码:
#include "libmatrixp.h" 其中引入了很多函数和类, 留待后面解释。

5.3 编译链接执行
将步骤 2 中生成的 4 个文件拷贝到本项目所在目录, 然后
在链接选项中加入两个库 : libmatrixp.lib , mclmcrrt.lib 。

其 中 libmatrixp.lib 是在步骤 2 中生成的 lib 库, 而 mclmcrrt.lib/mclm-
crrt.dll 提供了 Matlab 的运行时支持功能。

编译链接后, 执行会得到以下结果:
The value of added m atrix is:
2 4 6 8 10 12 14 16 18
The value of the multiplied matrix is: 30 36 42 66 81 96 102 126 150
The eigenvalu es of the first matrix are: 16.1168 -1.1168
#include "stdafx.h"
void *run_main(void *x) {
int *err = (int *)x;
if (err == NULL) return 0;
if (! mclInitializeApplication(NULL,0)) {
std::cerr << "could not initialize the application properly"
<< std::endl; *err = -1; return x; }
if( ! libmatrixpInitialize() ) {
std::cerr << "could not initialize the library properly"
<< std::endl; *err = -1; } else {
try {
// Create input data
double data[] = {1,2,3,4,5,6,7,8,9};
mwArray in1(3, 3, mxD OU BL E_C L AS S, mxREAL); mwArray in2(3, 3, mxD OU BL E_C L AS S, mxREAL);
in1.SetData(data, 9); in2.SetData(data, 9); // Create output array mwArray out;
// Call the library function add matrix(1, out, in1, in2);
// Display the return value of the library function
std::cout << "The value of added m atrix is:" << std::endl;
%MATLAB_HOME%\extern\lib\win32\microsoft\msvc71
%MATLAB_HOME%\extern\include
std::cout << out << std::endl; multiplymatrix(1, out, in1, in2);
std::cout << "The value of the multiplied matrix is:"
<< std::e ndl;
std::cout << out << std::endl; eigmatrix(1, out, in1);
std::cout << "The eigenvalues of the first matrix are:"
<< std::e ndl;
std::cout << out << std::endl; }
catch (const mwException& e) {
std::cerr << e.wh at() << std::endl; *err = -2; }
catch (...) {
std::cerr << "Unexp ected error thrown " << std::endl;
*err = -3; }
// Call the application and library termination routine
libmatrixpTerminate(); }
mclTerminateApplication(); return 0; }
int main() {
int err = 0; run_main(&err); return err; }
得到每一维的长度, 以上面的 2*3*4 矩阵为例:
如果是第 一 次 执 行 , 还会提示解压缩了 CTF 文 件 , 生 成 了 MCR 目录。

5.4 Driver 代码相关函数
5.4.1. mclInitializeA pplication 和 mclTerminateApplication MCR 的初始化和结束函数 。

MCR 即 Matlab Component Runtime , 即 Matlab 的运行时支持环境 。

由 Matlab 生 成 的 组 件、 DLL 或者程序必须有 MCR 才能运行。

mwArray dim = a.GetDime nsions(); int dim1 = dim.Get(1,1); int dim2 = dim.Get(1,2); int dim3 = dim.Get(1,3);
结果 dim1 为 2, dim2 为 3, dim3 为 4。

得到矩阵里面存储的元素个数:
int n = a.NumberOfElements();
得到每个元素所占的字节数:
所 以 在 Driver 代码中必须初始化 MCR , 出 MCR 。

在 代 码 退 出 前 退 int size = a.ElementSize();
对 于 mxDOUBLE_CLASS 来 说 , 占 用 8 个 字 节 。

GLE_CLASS 和 mxINT32_CLASS 都占用 4 个字节。

将矩阵转换为字符串:
mxSIN- 5.4.2. %LibName%Initialize () 和%LibName%Terminate
这两个函数由 mcc 生成, 包含在头文件中, 是 dll 的初始 化和退出函数。

这两个函数的调用必须包含在 mclInitializeAp- plication 和 mclTerminateApplication 之间。

5.4.3. mwArray
mwArray 是 Matlab 矩阵类型的 C++封装类, 常被用来作为 向 C++代码提供输入输出的参数。

mwArray 提供了一系列的构造函数、 成员函数和运算符来
创建、 操作矩阵对象。

mwArray 对象创建举例:
得到结果:
上面的语句创建了一个 3*3 的矩阵, 类型是 double 实数。

又如:
创建了一个 2*3 的元胞矩阵。

下面的语句将一个 C++数组的值赋给了 mwArray :
下面的语句从一个 mwArray 取出需要的数值:
5.4.5. mwArray 的行列顺序和起始数值
在 C++中, 二维数组是先行后列 , 而使用 SetData 方法将 数据导入 mwArray 时, 是先列后行。

因此会出现如下结果: double data[3][3] = {1,2,3,4,5,6,7,8,9};
mwArray in1(3, 3, mxD OU BL E_C L AS S, mxREAL); in1.SetData((double*)data, 9); mwString strIn1 = in1.ToString(); std::cout<<strIn1<<std::endl;
5.4.4. mwArray 的使用
创建一个 3*3 的二维矩阵, 代码如下:
运行结果是:
1 2 3
4 5 6
7 8 9
创建一个多维矩阵, 例如 2*3*4 的三维矩阵:
C++ 中 , 数 组 序 号 从 0 开 始 , 而 mwArray 中 序 号 从 1 开 始。

注意下面的代码, 同时在原始数组和矩阵中取第 1 行, 第 3 列的数据:
得到维数, 例如二维就是 2, 三维就是 3:
double yy = data[0][2];
int nDims=a.NumberOfDimensions();
int dims[3] = {2,3,4};
mwArray a(3, dims, mxDOUBLE_CLASS);
mwArray in1(3, 3, mxD OU BL E_C L AS S, mxREAL);
double data[4] = {1.0, 2.0, 3.0, 4.0}; double x;
mwArray a(2, 2, mxDOU BL E_C LA SS); a.SetData(data, 4);
x = a.Get(1,1); // x = 1.0 x = a.Get(2, 1, 2); // x = 3.0 x = a.Get(2, 2, 2); // x = 4.0 double data[] = {1,2,3,4,5,6,7,8,9};
mwArray in1(3, 3, mxD OU BL E_C L AS S, mxREAL); in1.SetData(data, 9);
mwArray c(2, 3, mxCELL_CLASS);
mwArray in1(3, 3, mxD OU BL E_C L AS S, mxREAL);
(:,:,1) =
1 3 5
2 4 6 (:,:,2) =
7 9 11 8 10 12 (:,:,3) = 13 15 17 14 16 18 (:,:,4) = 19 21 23 20 22
24
double dataa[]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18, 19,20,21,22,23,24}; int dims[3] = {2,3,4};
mwArray a(3, dims, mxSINGLE_CLASS); a.SetData(dataa,24);
std::cout<<(const char*)a.ToString()<<std::endl;
0.0000
贝到 exe 所在目录下。

对于使用了 Matlab 创建的 dll 的应用程序来说, 在发布时 还多了两个手续:
第一, 在目标机器上需要安装 MCR , 若目标机器是 Win-
dows 系统, MCR 的安装仅仅需要执行 MCRInstaller.exe 即可。

第 二 , 将 dll 和 相 应 的 CTF 文 件 拷 贝 到 Path 路 径 中 或 者 exe 所在目录下。

因 此 , 在制作发布程 序 时 , 需 要 将 MCRInstaller.exe 、 dll
和 CTF 文件放入其中, 并制定好执行顺序和所在目录即可。

结果原始数组中的结果是 3, 而矩阵中的结果是 7。

5.4.6. 向 mwArray 中导入数据的方法
假设一个 3*4 的数据值如下:
想要导入一个 mwArray , 则必须先做一个转换:
结语
至 此 为 止 , m 代码已经可以转 换 为 dll 进行混合编程了 , 并且也可以发布到客户端进行安装运行了。

其中涉及到的文件 如表 1 所示。

7 表 1 过程文件列表
工程中引用
程序时使用 或者采用一维数组来转换:
int mydata_x[12]; Matlab 是一个很好的算法设计、 调试和测试工具, 其 m 代
码功能强大、 编写简单、 调试便利, 可大幅提高程序员的算法 设计效率。

但 m 代码在普通的应用程序开发时所需的背景知
识复杂, 步骤繁多。

文中介绍了一种将 Matlab 代码转换为 C++
DLL 进行混合编程的方法, 该方法清晰有效, 可帮助 C++程序
员利用 Matlab 进行算法的快速开发、 调试与发布。

(收稿日期: 2011-10-29)
6 发布
对于一般的应用程序来说 , 如果使用了外来的 dll , 那 么 在发布程序时仅仅需要将这些 dll 拷贝到 Path 路径中, 或者拷
int mydata[3][4] = {
1,2,3,4, 5,6,7,8, 9,10,11,12 };
int index = 0;
for (int j = 0; j<4;++j) {
for (int i = 0; i<3; ++i) {
mydata_x[index] = mydata[i][j]; ++index; } }
mwArray mydata_m(3,4,mxINT32_CL AS S,mxR EA L);
mydata_m.SetData((int*)mydata_x,12); std::cout<<mydata_m<<std::endl;
文件名称
文件来源 文件用途 add ma t r i x.m 、 multiply - mat r i x.m 、 eig mat r i x.m 由 M 程序员编写 设计算法
libmatrixp.h 由 mcc 命令生成 头文件, 由 C++程 序 员 在
libmatrixp.lib 由 mcc 命令生成 库 文 件 , C ++ 程 序 员 链 接
libmatrixp.dll 由 mcc 命令生成 dll 文件, 程序运行时使用
libmatrixp.ctf 由 mcc 命令生成 C TF 文件, 程
序 运 行 时 使 用
mclmcrrt.lib
由 Mat l a b 提供
库 文 件 , 支 持 m 代 码 dl l 的链接
D r i ve r 代码
由 C++程序员编写
它将 C ++代码和 M 代码生 成的文件组合起来编译链 接为应用程序
M C R I n stal l e r.e xe
由 Mat l a b 提供, 一般位于% MATLAB_HOME%\toolbox\ compiler\deploy \win32
为客户端提供 Mat l ab 运行
环境 int mydata[3][4] =
{
1,2,3,4, 5,6,7,8, 9,10,11,12 };
int mydata_x[4][3]; for (int i = 0; i<3;++i) {
for (int j = 0; j<4; ++j) {
mydata_x[j][i] = mydata[i][j]; } }
mwArray mydata_m (3,4,mxINT32_CL AS S,
mxREAL);
mydata_m.SetData((int*)mydata_x,12); std::cout<<mydata_m<<std::endl;
1 2 3 4 5 6 7 8 9 10 11 12
double xx = in1.Get(2,1,3);。

相关文档
最新文档