Matlab在语法上具有诸多的便利性,可以把matlab的代码(.m文件)为动态链接库dll,之后在c++中调用。本文讲解如何操作以及一些细节。
测试环境:
- 操作系统:windows10
- C++:visual studio 2017
- Matlab版本:Matlab R2020b
Matlab代码编译dll
第一步:编写matlab代码。这里以计算标量与向量的乘积为例。选用该实例的原因是为了演示C++调用matlab的函数时如何返回数组。
function [c]=example(a,v)
%v为一个向量
%a为double
%函数返回标量与向量的乘积
num=length(v);
c=zeros(1,num);
for i=1:num
c(i)=a*v(i);
end
end
第二步:配置编译环境。在matlab的命令行窗口中输入mbuild -setup,matlab会自动搜索系统安装的vs编译环境。点击其中的Microsoft Visual C++ 2017 (C) 和mex -setup C++ -client MBUILD 配置好环境。
>> mbuild -setup
MBUILD 配置为使用 'Microsoft Visual C++ 2017 (C)' 以进行 C 语言编译。
要选择不同的 C 编译器,请从以下选项中选择一种命令:
Microsoft Visual C++ 2017 (C) mex -setup:C:\Users\wanyz\AppData\Roaming\MathWorks\MATLAB\R2020b\MBUILD_C_win64.xml C -client MBUILD
Microsoft Visual C++ 2019 (C) mex -setup:'C:\Program Files\Polyspace\R2020b\bin\win64\mexopts\msvc2019.xml' C -client MBUILD
要选择不同的语言,请从以下选项中选择一种命令:
mex -setup C++ -client MBUILD
mex -setup FORTRAN -client MBUILD
第三步: 编译matlab的代码为动态链接库。在matlab的命令行窗口中输入deploytool命令,打开matlab compiler,选择Library Compiler。
在弹出的窗口的TYPE中选中C++Shared Library,在EXPORTED FUNCTIONS中选中写好的example.m文件,接着点击Package按钮。注意一定要选中example.m文件。
如果没有错误,将打包成功。硬盘上将生成三个文件夹:for_redistribution、for_redistribution_files_only和for_testing。其中for_redistribution_files_only是需要使用的文件,包含编译好的lib文件、h文件和dll文件,即example.h、example.lib和example.dll。
C++调用matlab的dll
第一步:新建C++的控制台程序,选择64位解决方案,配置好包含文件和库文件的路径。
- 包含目录:C:\Program Files\Polyspace\R2020b\extern\include; ../../for_redistribution_files_only
- 库目录:C:\Program Files\Polyspace\R2020b\extern\lib\win64\microsoft;../../for_redistribution_files_only
第二步:链接器->输入->附加依赖项,添加如下库文件:example.lib和mclmcrrt.lib
第三步:编写C++调用代码。我们打开生成的example.h文件看看接口函数:
extern LIB_example_CPP_API void MW_CALL_CONV example(int nargout, mwArray& c, const mwArray& a, const mwArray& v);
从上述接口函数我们可以看出:
- 函数返回的是void,跟我们matlab定义的返回数组不同
- 函数的参数比我们原matlab代码多了两个,即第一个int nargout和mwArray& c。此处的mwArray是一个c++的类,可以理解为数组。多了的这两个参数即是定义函数的返回值。其中mwArray& c是引用的方式传递的,即外部传入的值在函数内部会修改。int nargout则表示返回值的个数。注意该个数不是mwArray& c这个数组的大小,而是表示返回多少值。由于matlab的函数可以返回多个值,而C++的函数只能返回一个值,所以经过转换以后,会将所有的返回值都引用参数的方式放在函数中,int nargout即表示原始matlab代码返回多少个值。
- 原始matlab代码中的参数全部边为了mwArray类型
代码运行的顺序:
- 第一步:调用mclInitializeApplication进行程序初始化。
- 第二步:调用exampleInitialize进行初始化。此处的函数名根据前边命名不同而不同
- 第三步:调用dll中的函数进行计算,保存返回的结果
- 第四步:调用mclTerminateApplication函数终止程序
按照上述逻辑,调用代码如下:
#include <iostream>
#include "example.h"
int main()
{
//初始化
if (!mclInitializeApplication(NULL, 0))//程序初始化
{
std::cout << "failed" << std::endl;
return -1;
}
exampleInitialize();//函数初始化
//创建输入参数
mwArray a(1, 1, mxDOUBLE_CLASS);//创建1*1的double型数组,作为函数的第三个参数(原matlab代码的第一个参数)
a(1, 1) = 2;
mwArray v(1, 2, mxDOUBLE_CLASS);//创建1*2的double型数组,作为函数的第四个参数(原matlab代码的第二个参数)
double v_c[] = { 1,2 };
v.SetData(v_c, 1*2);//使用SetData为数组赋值,第二个参数为数组的元素个数,即1*2
mwArray c(1, 2, mxDOUBLE_CLASS);//创建1*2的double数组,作为函数的第二个参数(原matlab代码的返回值)
int nargout = 1;//定义返回值的个数,原matlab代码只返回一个值,这里设置为1
//调用dll中的函数计算
example(nargout, c, a, v);
//输出计算结果。计算结果保存在c中,注意数组与matlab一样从1开始
std::cout << "Result = (" << c(1, 1) << "," << c(1, 2) << ")" << std::endl;
//终止程序
mclTerminateApplication();
}
上述代码计算标量2与向量(1,2)的乘积,计算结果如下:
以上即是使用c++调用maltab动态库中函数的方法。