c++动态生成数组大小_C++/MATLAB 联合编程:C++中调用MATLAB编译出来的动态库

目录

前言mwArrayBrief构造函数成员方法C++ 调用 MATLAB 实例前期准备无返回值有返回值注意事项

前言

之前我写过一篇 MATLAB与C语言的混合编程,那个是用 mex 命令 来编译 .C 文件 生成 .mexw64 文件来给 MATLAB 调用。注意啊,是在 MATLAB中 调用 C函数。

现在,在这偏推送里讲的是:在 C++中 调用 MATLAB函数 !

其实,我之前也没怎么学在C++中调用MATLAB,突然学这个是因为 上上周老师催着要一个原型发给客户。但是核心的算法目前仅仅是用MATLAB验证了正确性,还没有用C++写。如果核心的算法用 C++ 来写的话估计要花好久(毕竟也就学了一个学期多点的C++)。所以为了赶时间,我就打算用 MATLAB 把核心的算法打包成动态,然后拿去给C++调用。

简单展示下还没做完的东西吧:

1deb0559b24fad611f7b4eb07f3a496e.png

941c5aa0041e27d674b9cb4af3b8ae61.png

不多说废话了,进入正题。

mwArray

关于 mwArray 的构造函数 以及 其成员方法 部分,完全是按照官网上的 文档复制过来的,有一些关于稀疏矩阵的方法我这里没放,我平时也没解过大型的方程组,所以稀疏矩阵这块也没怎么用,也就没有花时间去了解它。

Brief

Class used to pass input/output arguments to C++ functions generated by MATLAB Compiler SDK

用于将输入/输出参数传递给由MATLAB Compiler SDK生成的C ++函数的类。

使用mwArray类将输入/输出参数传递给由MATLAB生成的 C++ 接口函数。在MATLAB中所有的数据均由数组表示,这个类就是是对MATLAB中数组的封装。mwArray类提供必一些构造函数,方法以及运算符,用于数组的创建和初始化 以及 简单索引方式取值。

构造函数

1. 创建 空的 数组

/// 空的 数组,元素类型预定为 double; 构造函数:mwArray(mxClassID mxID)

2. 二维数组

/// 二维数组 构造函数:mwArray(mwSize num_rows, mwSize num_cols, mxClassID mxID, mxComplexity cmplx = mxREAL)

3. 三维数组/多维数组

/// 三维数组 mwArray(mwSize num_dims, const mwSize* dims, mxClassID mxID, mxComplexity cmplx = mxREAL)

其实 二维数组 也可以用这样的方式来创建

4. 一维字符数组(字符串)

/// 一维字符数组 mwArray(const char* str)

5. 多行字符串

/// 多行字符串,不要求每行字符个数相等 mwArray(mwSize num_strings,const char ** str)

6. 结构体数组

/// 二维 结构体数组 mwArray(mwSize num_rows, mwSize num_cols, int num_fields, const char** fieldnames)

这个可能稍微难理解一点,多看几眼这个构造函数,这个构造函数就是说明结构体数组有 几行 几列,几个域名,每个域名具体是什么。对于结构体值的设置,看一下下面的第30个成员方法。

7. 多维结构体数组

略,我都没碰见过,就不写这个了。

8. 拷贝构造函数(深拷贝)

mwArray(const mwArray& arr)

9. 标量

/// 标量 实数:mwArray( re);虚数:mwArray( re,  im)
成员方法

基本复制的官网上的,基本都没改。

1. 深拷贝 mwArray Clone() const

mwArray a(2, 2, mxDOUBLE_CLASS);

2. 浅拷贝(公用同一个地址的值)mwArray SharedCopy() const

mwArray a(2, 2, mxDOUBLE_CLASS);

3. 把数组 序列化 为 字节。mwArray Serialize() const

mwArray a(2, 2, mxDOUBLE_CLASS);

反序列化成原始形势:mwArray::Deserialize().

4. 确定数组的类型 mxClassID ClassID() const

mwArray a(2, 2, mxDOUBLE_CLASS);

5. 确定数组类型元素的大小(以字节为单位)size_t ElementSize()const

mwArray a(2, 2, mxDOUBLE_CLASS);

6. 确定数组元素的个数 mwSize NumberOfElements() const

mwArray a(2, 2, mxDOUBLE_CLASS);

7. 确定数组的维数 mwSize NumberOfDimensions() const

mwArray a(2, 2, mxDOUBLE_CLASS);

8. 确定结构体数组中的字段数(如果这个mwArray变量不是结构体类型则返回0)int NumberOfFields() const

const 

9. 获取 结构体的 第 index 个字段名 mwString GetFieldName(int index);如果mwArray变量不是结构体 则抛出异常

const 

10. 返回数组每个维度的大小(比如 几行几列):mwArray GetDimensions() const。返回的其实也是数组

mwArray a(2, 2, mxDOUBLE_CLASS);

11. 判断数组是否为空 bool IsEmpty() const

mwArray a;
bool b = a.IsEmpty();
std::cout <"11.IsEmpty(): " <std::endl <std::endl;

12. 判断是否是 数值数组 bool IsNumeric() const

mwArray a(2, 2, mxDOUBLE_CLASS);

13. 判断是否是 复数 数组 bool IsComplex() const

mwArray a(2, 2, mxDOUBLE_CLASS, mxCOMPLEX);

14. 判断两个数组是否相等(逐字节判断)bool Equals(const mwArray& arr) const

mwArray a(2, 2, mxDOUBLE_CLASS);

所以就算你用相同的数据来初始化两个不同类型的数组(如mxINT_CLASS 和 mxDOUBLE_CLASS),其结果也可能是不相等。也就是这个方法只能用于两个像同类型的数组来判断是否相等

15. 把mwArray数组转化成字符串输出 mwString ToString()const

mwArray a(2, 2, mxDOUBLE_CLASS, mxCOMPLEX);

16. 把一个 实数矩阵 转化为 复数矩阵 void MakeComplex();原地修改;如果不是数值矩阵会抛出异常

double rdata[

17. 根据索引获取数组的中的值 mwArray Get(mwSize num_indices, …)

double data[

Note: 索引从 1 开始!,第一个参数可以是数组的维度,紧接着后面的系列参数表示 取 第几行第几列 或者 第几页的元素值。以二维数组为例,第一个参数正常写成 2 ,后面两个参数分别代表 行 和 列。
如果第一个参数是 1,则应该只输入两个参数才对。假设第2个参数是 n , 那么将按照列来数 第 n 个元素值

18. 根据 域名 和 索引 获取结构体数组中 第 索引 处的 域名下的值 mwArray Get(const char* name, mwSize num_indices, …)

const 

Note:后面索引的问题,同上

19. 获取数组的 实部 和 虚部 mwArray Real()mwArray Imag()

double rdata[

20. 用一个mwArray数组的值来赋值给另一个mwArray(用的同一个地址上的值);void Set(const mwArray& arr)

mwArray a(2, 2, mxDOUBLE_CLASS);

21. 从mwArray 中拷贝 len 个数值到 一个C标准数组中 void GetData(* buffer, mwSize len) const

double rdata[

22. 从 mwArray 字符数组中拷贝 len 个 字符 到一个 char[] 数组中 void GetCharData(mxChar* buffer, mwSize len) const

6] = {

23. 给mwArray 数组赋值,从一个 标准 C 数组中 拷贝前 len 个数值 到 mwArray 数组中 void SetData(* buffer, mwSize len)

double rdata[

24. 给逻辑数组赋值 void SetLogicalData(mxLogical* buffer, mwSize len)

4] = {

25. 给mwArray字符数组赋值 void SetCharData(mxChar* buffer, mwSize len)

6] = {

26. 判断数值是否有限

static 

27. 判断数值是否无穷

static 

28. 判断数值是否 NaN

static 

29. mwArray operator()(mwIndex i1, mwIndex i2, mwIndex i3, …, )

double data[

和MATLAB中一样的获取值的方法

30. mwArray operator()(const char* name, mwIndex i1, mwIndex i2, mwIndex i3, …, )

const 

Note:获取结构体的值

31. 给mwArray数组中的某个元素设置某个标量 mwArray& operator=(const& x)

mwArray a(2, 2, mxDOUBLE_CLASS);

C++ 调用 MATLAB 实例

这里只是举了两个简单的例子,通过MATLAB来画图。

前期准备

首先设置MATLAB的编译器 主要设置C++编译器,装好 VS2017,然后

mbuild -setup

分别点下那两个箭头,然后就好了。如果你用的MinGW编译器则配置起来多几步,这里就不多说了,Win中还是最好用VS的编译器吧。

4c8ae9f7ea0dc845a2c8e71ff3d2ffdd.png


还有就是你需要引入 MATLAB 的库,和 MCR 那些相关的,之前在 搭建VS2017_QT_MATLAB开发环境 这偏推送种写过,习惯用VS的同学可以看这篇推送去。不过,我现在用的是 CLion ,用 CMake 来引入 MATLAB 的库,相关的 CMakeLists.txt 的写法如下

###################################### MATLAB库 ######################################
# 把包含 MATLAB 那6个lib所在的头文件的目录进来(固定的)
include_directories("C:/Program Files/Polyspace/R2019a/extern/include")
include_directories("C:/Program Files/Polyspace/R2019a/extern/include/win64")

# 把我们用 MATLAB 生成的那些lib的头文件的目录包含进来(我就放在当前目录下)
INCLUDE_DIRECTORIES("./")

# 把我们用 MATLAB 生成的那些 lib所在的 目录 链接 进来(我也放在当前目录下)
link_directories(./)

# 把我们用MATLAB生成的那些 lib 所 依赖的 MATLAB的库目录路径 链接进来
link_directories("C:/Program Files/Polyspace/R2019a/extern/lib/win64/microsoft")
# 链接 我们用MATLAB生成的那个lib 所依赖的 6个库文件 链接程序中,供那个库使用
link_libraries(
        "C:/Program Files/Polyspace/R2019a/extern/lib/win64/microsoft/libmex.lib"
        "C:/Program Files/Polyspace/R2019a/extern/lib/win64/microsoft/libmx.lib"
        "C:/Program Files/Polyspace/R2019a/extern/lib/win64/microsoft/libmat.lib"
        "C:/Program Files/Polyspace/R2019a/extern/lib/win64/microsoft/libeng.lib"
        "C:/Program Files/Polyspace/R2019a/extern/lib/win64/microsoft/mclmcr.lib"
        "C:/Program Files/Polyspace/R2019a/extern/lib/win64/microsoft/mclmcrrt.lib"
)


add_executable(target main.cpp)

target_link_libraries(target PUBLIC 生成的MATLAB库.lib)

Note:如果生成的 MATLAB库对应的lib文件没有和 主CMakeList.txt放一块的话,就必须要使用绝对路径!然后链接到目标文件中。

无返回值

MATLAB代码:

function ShowXY(x, y, XRange, YRange)

ax = axes('Box', 'on', 'XLim', XRange, 'YLim', YRange);
plot(x, y, 'Parent', ax)

end

使用 mcc 命令来编译 m代码

mcc -W cpplib:MyLib -T link:lib ShowXY.m

dc3667bb52ca8ca0a4848fdf5628862b.png

看一下生成的这个MyLib头文件

拖到最后,你会看到一个 CPP API;

93c1370a83dd9810a0c22416dc2c007b.png

可以看到 无输出的 C++ 的接口和原来的M文件的函数接口一摸一样。在它前面还有个 C API,那个是C的接口,这里用不上。

但是,前面还有有两个 C API 是需要用的:

072054db3f8215fadbe5c26e43da155c.png

分别是启动这个库的函数,和终结这个库的函数!

C++代码

#include "MyLib.h"

结果:

8c1243f27471b1b764db006183136df1.png

有返回值

这里,返回两个变量值

MATLAB代码

function [mean_x, mean_y] = ShowXY(x, y, XRange, YRange)

ax = axes('Box', 'on', 'XLim', XRange, 'YLim', YRange);
plot(x, y, 'Parent', ax)

mean_x = mean(x);
mean_y = mean(y);

end

相同的操作编译成 库,库的名字还和上面一样, 具体的操作略

4d9f19ca55dc93012f5860ef53b304ce.png

假设,MATLAB函数有 nargout 个 返回值,那么有返回值的 接口和没返回值得接口区别在于:有返回值的接口的前 nargout+1 个参数都是用来描述MATLAB函数的返回值。紧接着后面的若干个参数才是MATLAB函数的输入。具体看下面的代码实例

C++ 代码

#include "MyLib.h"

结果:

c4e062c9bac4ff1e6e93e800fa2df5ed.png

注意事项

调用MATLAB库生成多个MATLAB的figure

如果你调用MATLAB所生成的库函数生成多个 MATLAB 中的figure,可能会崩溃死。是因为:可能会多次高频地触发MATLAB的figure的 WindowButtonMotionFunction。这会造成崩溃!

解决办法,网上说的我试了,反正我没成功。后面是采用MATLAB的print函数保存figure窗口中的图形到图片中,然后显示图片就行,一样的效果!

最好现在MATLAB中测试一下函数有没有问题,再编译!

--- mwArray 的官网链接

https://ww2.mathworks.cn/help/compiler_sdk/cxx/mwarray.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值