将 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
字符串转数组matlab2 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小时内删除。
发表评论