将 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 文件。
< 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
字符串转数组matlab
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 的安装仅仅需要执行 即可。
第 二 ,  将 dll 和 相 应 的 CTF 文 件 拷 贝 到 Path 路 径 中 或 者 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 文件,  程序运行时使用
序 运 行 时 使 用
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);

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