C++/MATLAB 联合编程:C++中调用MATLAB编译出来的动态库
欢迎关注我的微信公众号:MatlabGUI QtCPP等学习记录
目录
前言mwArrayBrief构造函数成员方法C++ 调用 MATLAB 实例前期准备无返回值有返回值注意事项
前言
之前我写过一篇 MATLAB与C语言的混合编程,那个是用 mex 命令 来编译 .C 文件 生成 .mexw64 文件来给 MATLAB 调用。注意啊,是在 MATLAB中 调用 C函数。
现在,在这偏推送里讲的是:在 C++中 调用 MATLAB函数 !
其实,我之前也没怎么学在C++中调用MATLAB,突然学这个是因为 上上周老师催着要一个原型发给客户。但是核心的算法目前仅仅是用MATLAB验证了正确性,还没有用C++写。如果核心的算法用 C++ 来写的话估计要花好久(毕竟也就学了一个学期多点的C++)。所以为了赶时间,我就打算用 MATLAB 把核心的算法打包成动态,然后拿去给C++调用。
简单展示下还没做完的东西吧:
不多说废话了,进入正题。
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. 创建 空的 数组
[code]/// 空的 数组,元素类型预定为 double; 构造函数:mwArray(mxClassID mxID) mwArray a(mxDOUBLE_CLASS); /// Note:mxClassID有以下若干种(下同) mxDOUBLE_CLASS mxSINGLE_CLASS mxINT8_CLASS mxUINT8_CLASS mxINT16_CLASS mxUINT16_CLASS mxINT32_CLASS mxUINT32_CLASS mxINT64_CLASS mxUINT64_CLASS
2. 二维数组
[code]/// 二维数组 构造函数:mwArray(mwSize num_rows, mwSize num_cols, mxClassID mxID, mxComplexity cmplx = mxREAL) // 行 和 列 都是 mwSize 类型的值,mwSize 是 size_t 的 typedef, // size_t 在win64种是 unsigned __int64 的typedef;在其他中是 unsigned int 的typedef mwSize num_rows = 3; mwSize num_cols = 3; mwArray b(num_rows, num_cols, mxDOUBLE_CLASS);
3. 三维数组/多维数组
[code]/// 三维数组 mwArray(mwSize num_dims, const mwSize* dims, mxClassID mxID, mxComplexity cmplx = mxREAL) mwSize num_dims = 3; // 数组的维数 const mwSize dims[3] = {5, 5, 3}; // 每个维度具体的值 mwArray c(num_dims, dims, mxDOUBLE_CLASS);
其实 二维数组 也可以用这样的方式来创建
4. 一维字符数组(字符串)
[code]/// 一维字符数组 mwArray(const char* str) std::string str = "Mitch Hong"; mwArray d(str.c_str());
5. 多行字符串
[code]/// 多行字符串,不要求每行字符个数相等 mwArray(mwSize num_strings,const char ** str) const mwSize num_strings = 3; const char* strs[num_strings] = {"Mitch", "Hong", "Miao"}; mwArray e(num_strings, strs);
6. 结构体数组
[code]/// 二维 结构体数组 mwArray(mwSize num_rows, mwSize num_cols, int num_fields, const char** fieldnames) // Note: 结构体的每个 域值 也 必须是 mwArray 类型。在后面 方法30 中写了一个 设置结构体域值的例子 num_rows = 2; // 前面声明且定义过,这里直接赋值 num_cols = 2; // 前面声明且定义过,这里直接赋值 int num_fields = 2; const char* fields[2] = {"Name", "Sex"}; mwArray f(num_rows, num_cols, num_fields, fields);
这个可能稍微难理解一点,多看几眼这个构造函数,这个构造函数就是说明结构体数组有 几行 几列,几个域名,每个域名具体是什么。对于结构体值的设置,看一下下面的第30个成员方法。
7. 多维结构体数组
略,我都没碰见过,就不写这个了。
8. 拷贝构造函数(深拷贝)
mwArray(const mwArray& arr)
9. 标量
[code]/// 标量 实数:mwArray(<type> re);虚数:mwArray(<type> re, <type> im) mwArray g(mxDouble); mwArray h(mxDouble, mxDouble);
成员方法
基本复制的官网上的,基本都没改。
1. 深拷贝
mwArray Clone() const
[code]mwArray a(2, 2, mxDOUBLE_CLASS); mwArray b = a.Clone();
2. 浅拷贝(公用同一个地址的值)
mwArray SharedCopy() const
[code]mwArray a(2, 2, mxDOUBLE_CLASS); mwArray b = a.SharedCopy();
3. 把数组 序列化 为 字节。
mwArray Serialize() const
[code]mwArray a(2, 2, mxDOUBLE_CLASS); mwArray b = a.Serialize(); std::cout << "3.Serialize():\n" << b << std::endl << std::endl;
反序列化成原始形势:mwArray::Deserialize().
4. 确定数组的类型
mxClassID ClassID() const
[code]mwArray a(2, 2, mxDOUBLE_CLASS); mxClassID id = a.ClassID(); std::cout<< "4.ClassID():\nid == mxDOUBLE_CLASS: " << (id == mxDOUBLE_CLASS) << std::endl << std::endl;
5. 确定数组类型元素的大小(以字节为单位)
size_t ElementSize()const
[code]mwArray a(2, 2, mxDOUBLE_CLASS); int size = a.ElementSize(); std::cout << "5.ElementSize(): " << size << std::endl << std::endl;
6. 确定数组元素的个数
mwSize NumberOfElements() const
[code]mwArray a(2, 2, mxDOUBLE_CLASS); int n = a.NumberOfElements(); std::cout << "6.NumberOfElements(): " << n << std::endl << std::endl;
7. 确定数组的维数
mwSize NumberOfDimensions() const
[code]mwArray a(2, 2, mxDOUBLE_CLASS); int n = a.NumberOfDimensions(); std::cout << "7.NumberOfDimensions(): " << n << std::endl << std::endl;
8. 确定结构体数组中的字段数(如果这个mwArray变量不是结构体类型则返回0)
int NumberOfFields() const
[code]const char* fields[] = {"a", "b", "c"}; mwArray a(2, 2, 3, fields); int n = a.NumberOfFields(); std::cout << "8.NumberOfFields(): " << n << std::endl << std::endl;
9. 获取 结构体的 第 index 个字段名
mwString GetFieldName(int index);如果mwArray变量不是结构体 则抛出异常
[code]const char* fields[] = {"a", "b", "c"}; mwArray a(2, 2, 3, fields); mwString tempname = a.GetFieldName(1); std::cout << "9.GetFieldName(1): " << tempname << std::endl << std::endl;
10. 返回数组每个维度的大小(比如 几行几列):
mwArray GetDimensions() const。返回的其实也是数组
[code]mwArray a(2, 2, mxDOUBLE_CLASS); mwArray dims = a.GetDimensions(); std::cout << "10.GetDimensions(): " << dims << std::endl << std::endl;
11. 判断数组是否为空
bool IsEmpty() const
[code]mwArray a; bool b = a.IsEmpty(); std::cout << "11.IsEmpty(): " << b << std::endl << std::endl;
12. 判断是否是 数值数组
bool IsNumeric() const
[code]mwArray a(2, 2, mxDOUBLE_CLASS); bool b = a.IsNumeric(); std::cout << "12.IsNumeric(): " << b << std::endl << std::endl;
13. 判断是否是 复数 数组
bool IsComplex() const
[code]mwArray a(2, 2, mxDOUBLE_CLASS, mxCOMPLEX); bool b = a.IsComplex(); std::cout << "13.IsComplex(): " << b << std::endl << std::endl;
14. 判断两个数组是否相等(逐字节判断)
bool Equals(const mwArray& arr) const
[code]mwArray a(2, 2, mxDOUBLE_CLASS); mwArray b(2, 2, mxDOUBLE_CLASS); bool c = a.Equals(b); std::cout << "14.Equals(): " << c << std::endl << std::endl;
所以就算你用相同的数据来初始化两个不同类型的数组(如mxINT_CLASS 和 mxDOUBLE_CLASS),其结果也可能是不相等。
也就是这个方法只能用于两个像同类型的数组来判断是否相等
15. 把mwArray数组转化成字符串输出
mwString ToString()const
[code]mwArray a(2, 2, mxDOUBLE_CLASS, mxCOMPLEX); a.Real() = 1.0; a.Imag() = 2.0; std::cout << "15.ToString(): " << a.ToString() << std::endl << std::endl;
16. 把一个 实数矩阵 转化为 复数矩阵
void MakeComplex();原地修改;如果不是数值矩阵会抛出异常
[code]double rdata[4] = {1.0, 2.0, 3.0, 4.0}; double idata[4] = {10.0, 20.0, 30.0, 40.0}; mwArray a(2, 2, mxDOUBLE_CLASS); a.SetData(rdata, 4); a.MakeComplex(); a.Imag().SetData(idata, 4); std::cout << "16.MakeComplex(): " << a << std::endl << std::endl;
17. 根据索引获取数组的中的值 mwArray Get(mwSize num_indices, …)
[code]double data[9] = {1.0, 2.0, 3.0, 4.0, 5, 6, 7, 8, 9}; double x; mwArray a(3, 3, mxDOUBLE_CLASS); a.SetData(data, 9); x = a.Get(1,7); // 按列数,第7个元素值(7) std::cout << "17.Get(): " << x << std::endl; x = a.Get(2, 1, 3); // 第一行,第3列的元素值(7) std::cout << x << std::endl; x = a.Get(2, 2, 3); // 第二行,第3列的元素值(8) std::cout << x << std::endl << std::endl;
Note: 索引从 1 开始!,第一个参数可以是数组的维度,紧接着后面的系列参数表示 取 第几行第几列 或者 第几页的元素值。以二维数组为例,第一个参数正常写成 2 ,后面两个参数分别代表 行 和 列。
如果第一个参数是 1,则应该只输入两个参数才对。假设第2个参数是 n , 那么将按照列来数 第 n 个元素值
18. 根据 域名 和 索引 获取结构体数组中 第 索引 处的 域名下的值
mwArray Get(const char* name, mwSize num_indices, …)
[code]const char* fields[] = {"a", "b", "c"}; mwArray a(3, 3, 3, fields); mwArray c = a.Get("b", 2, 2, 3); // 第二行,第三列,处的结构体的 域名为 "b" 的阈值值 std::cout << "18.Get(): a(2, 3).b" << c << std::endl << std::endl;
Note:后面索引的问题,同上
19. 获取数组的 实部 和 虚部
mwArray Real();
mwArray Imag()
[code]double rdata[4] = {1.0, 2.0, 3.0, 4.0}; double idata[4] = {10.0, 20.0, 30.0, 40.0}; mwArray a(2, 2, mxDOUBLE_CLASS, mxCOMPLEX); a.Real().SetData(rdata, 4); a.Imag().SetData(idata, 4); std::cout << "19.Real() & Imag(): \n" << "a.Real(): " << a.Real() << std::endl; std::cout << "a,Imag(): " << a.Imag() << std::endl;
20. 用一个mwArray数组的值来赋值给另一个mwArray(用的同一个地址上的值);
void Set(const mwArray& arr)
[code]mwArray a(2, 2, mxDOUBLE_CLASS); mwArray b(2, 2, mxINT16_CLASS); mwArray c(1, 2, mxCELL_CLASS); c.Get(1,1).Set(a); c.Get(1,2).Set(b); std::cout << "20. Set(): " << c << std::endl << std::endl;
21. 从mwArray 中拷贝 len 个数值到 一个C标准数组中
void GetData(* buffer, mwSize len) const
[code]double rdata[4] = {1.0, 2.0, 3.0, 4.0}; double data_copy[4] ; mwArray a(2, 2, mxDOUBLE_CLASS); a.SetData(rdata, 4); a.GetData(data_copy, 4); std::cout << "21. GetData(): " << data_copy[0] << " " << data_copy[1] << " " << data_copy[2] << " " << data_copy[3] << std::endl << std::endl;
22. 从 mwArray 字符数组中拷贝 len 个 字符 到一个 char[] 数组中
void GetCharData(mxChar* buffer, mwSize len) const
[code]mxChar data[6] = {'H', 'e' , 'l' , 'l' , 'o' , '\0'}; mxChar data_copy[6] ; mwArray a(1, 6, mxCHAR_CLASS); a.SetCharData(data, 6); a.GetCharData(data_copy, 6); std::cout << "22. GetCharData(): " << data_copy << std::endl << std::endl;
23. 给mwArray 数组赋值,从一个 标准 C 数组中 拷贝前 len 个数值 到 mwArray 数组中
void SetData(* buffer, mwSize len)
[code]double rdata[4] = {1.0, 2.0, 3.0, 4.0}; double data_copy[4] ; mwArray a(2, 2, mxDOUBLE_CLASS); a.SetData(rdata, 4); a.GetData(data_copy, 4); // 把 a 中的值又拷贝给了 data_copy std::cout << "23. SetData(): " << a << std::endl << std::endl;
24. 给逻辑数组赋值 void SetLogicalData(mxLogical* buffer, mwSize len)
[code]mxLogical data[4] = {true, false, true, false}; mxLogical data_copy[4] ; mwArray a(2, 2, mxLOGICAL_CLASS); a.SetLogicalData(data, 4); a.GetLogicalData(data_copy, 4); // 把 a 中的值又拷贝给了 data_copy std::cout << "24. SetLogicalData(): " << a << std::endl << std::endl;
25. 给mwArray字符数组赋值 void SetCharData(mxChar* buffer, mwSize len)
[code]mxChar data[6] = {'H', 'e' , 'l' , 'l' , 'o' , '\0'}; mxChar data_copy[6] ; mwArray a(1, 6, mxCHAR_CLASS); a.SetCharData(data, 6); a.GetCharData(data_copy, 6); // 把 a 中的值又拷贝给了 data_copy std::cout << "25. SetCharData(): " << a << std::endl << std::endl;
26. 判断数值是否有限
[code]static bool mwArray::IsFinite(double x)
27. 判断数值是否无穷
[code]static bool mwArray::IsInf(double x)
28. 判断数值是否 NaN
[code]static bool mwArray::IsNaN(double x)
29. mwArray operator()(mwIndex i1, mwIndex i2, mwIndex i3, …, )
[code]double data[4] = {1.0, 2.0, 3.0, 4.0}; double x; mwArray a(2, 2, mxDOUBLE_CLASS); a.SetData(data, 4); x = a(1,1); x = a(1,2); x = a(2,2); std::cout << "29. :" << x << std::endl << std::endl;
和MATLAB中一样的获取值的方法
30. mwArray operator()(const char* name, mwIndex i1, mwIndex i2, mwIndex i3, …, )
[code]const char* fields[] = {"a", "b", "c"}; int index[2] = {1, 1}; mwArray a(1, 1, 3, fields); a("a", 1, 1) = mwArray("Mitch"); // 结构体的 域值 也必须是 mwArray! a("b", 1, 1) = mwArray("Hong"); // 结构体的 域值 也必须是 mwArray! a("c", 1, 1) = mwArray("Miao"); // 结构体的 域值 也必须是 mwArray! mwArray b = a("a", 1, 1); // b 是 "Mitch" std::cout << "30. :" << "a: " << a << std::endl << "b: " << b << std::endl << std::endl;
Note:获取结构体的值
31. 给mwArray数组中的某个元素设置某个标量
mwArray& operator=(const& x)
[code]mwArray a(2, 2, mxDOUBLE_CLASS); a(1,1) = 1.0; a(1,2) = 2.0; a(2,1) = 3.0; a(2,2) = 4.0; std::cout << "31. :" << a;
C++ 调用 MATLAB 实例
这里只是举了两个简单的例子,通过MATLAB来画图。
前期准备
首先设置MATLAB的编译器 主要设置C++编译器,装好 VS2017,然后
[code]mbuild -setup
分别点下那两个箭头,然后就好了。如果你用的MinGW编译器则配置起来多几步,这里就不多说了,Win中还是最好用VS的编译器吧。
还有就是你需要引入 MATLAB 的库,和 MCR 那些相关的,之前在 搭建VS2017_QT_MATLAB开发环境 这偏推送种写过,习惯用VS的同学可以看这篇推送去。不过,我现在用的是 CLion ,用 CMake 来引入 MATLAB 的库,相关的 CMakeLists.txt 的写法如下
[code]###################################### 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代码:
[code]function ShowXY(x, y, XRange, YRange) ax = axes('Box', 'on', 'XLim', XRange, 'YLim', YRange); plot(x, y, 'Parent', ax) end
使用 mcc 命令来编译 m代码
[code]mcc -W cpplib:MyLib -T link:lib ShowXY.m
看一下生成的这个MyLib头文件
拖到最后,你会看到一个 CPP API;
可以看到 无输出的 C++ 的接口和原来的M文件的函数接口一摸一样。在它前面还有个 C API,那个是C的接口,这里用不上。
但是,前面还有有两个 C API 是需要用的:
分别是启动这个库的函数,和终结这个库的函数!
C++代码
[code]#include "MyLib.h" #include <iostream> int main() { /// 调用 MATLAB 生成的库 前,先初始化这个库 if (!MyLibInitialize()) { return -1; } /// 准备数据 auto* x = new double[30]; auto* y = new double[30]; double XRange[2] = {0, 10}; double YRange[2] = {0, 20}; double step = 0.1; for (int i = 0; i < 30; ++i) { x[i] = step * i; y[i] = x[i] * x[i]; } /// 把数据转化成 mwArray mwArray x_mwArray(1, 30, mxDOUBLE_CLASS); mwArray y_mwArray(1, 30, mxDOUBLE_CLASS); x_mwArray.SetData(x, 30); y_mwArray.SetData(y, 30); mwArray XRange_mwArray(1, 2, mxDOUBLE_CLASS); mwArray YRange_mwArray(1, 2, mxDOUBLE_CLASS); XRange_mwArray.SetData(XRange, 2); YRange_mwArray.SetData(YRange, 2); /// 调用 MATLAB 生成的 库函数 ShowXY(x_mwArray, y_mwArray, XRange_mwArray, YRange_mwArray); /// 需要 阻止主线程的结束,不然这个窗口也只是一闪而过 std::cin.get(); std::cin.get(); /// 最后程序结束前终止这个库 MyLibTerminate(); return 0; }
结果:
有返回值
这里,返回两个变量值
MATLAB代码
[code]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
相同的操作编译成 库,库的名字还和上面一样, 具体的操作略
假设,MATLAB函数有 nargout 个 返回值,那么有返回值的 接口和没返回值得接口区别在于:有返回值的接口的前 nargout+1 个参数都是用来描述MATLAB函数的返回值。紧接着后面的若干个参数才是MATLAB函数的输入。具体看下面的代码实例
C++ 代码
[code]#include "MyLib.h" int main() { /// 调用 MATLAB 生成的库 前,先初始化这个库 if (!MyLibInitialize()) { return -1; } /// 准备输入数据 auto* x = new double[30]; auto* y = new double[30]; double XRange[2] = {0, 10}; double YRange[2] = {0, 20}; double step = 0.1; for (int i = 0; i < 30; ++i) { x[i] = step * i; y[i] = x[i] * x[i]; } /// 把数据转化成 mwArray mwArray x_mwArray(1, 30, mxDOUBLE_CLASS); mwArray y_mwArray(1, 30, mxDOUBLE_CLASS); x_mwArray.SetData(x, 30); y_mwArray.SetData(y, 30); mwArray XRange_mwArray(1, 2, mxDOUBLE_CLASS); mwArray YRange_mwArray(1, 2, mxDOUBLE_CLASS); XRange_mwArray.SetData(XRange, 2); YRange_mwArray.SetData(YRange, 2); /// 准备 MATLAB 函数的输出 int nargout = 2; mwArray meanX_mwArray(mxDOUBLE_CLASS); // 空的就行,只是要声明一下这个 变量 mwArray meanY_mwArray(mxDOUBLE_CLASS); /// 调用 MATLAB 生成的 库函数 ShowXY(nargout, meanX_mwArray, meanY_mwArray, x_mwArray, y_mwArray, XRange_mwArray, YRange_mwArray); /// 打印 MATLAB 函数的 输出 std::cout << "meanX_mwArray:\n" << meanX_mwArray << std::endl; std::cout << "meanY_mwArray:\n" << meanY_mwArray << std::endl; /// 需要 阻止主线程的结束,不然这个窗口也只是一闪而过 std::cin.get(); std::cin.get(); /// 最后程序结束前终止这个库 MyLibTerminate(); return 0; }
结果:
注意事项
调用MATLAB库生成多个MATLAB的figure
如果你调用MATLAB所生成的库函数生成多个 MATLAB 中的figure,可能会崩溃死。是因为:可能会多次高频地触发MATLAB的figure的
WindowButtonMotionFunction。这会造成崩溃!
解决办法,网上说的我试了,反正我没成功。后面是采用MATLAB的
最好现在MATLAB中测试一下函数有没有问题,再编译!
--- mwArray 的官网链接
https://ww2.mathworks.cn/help/compiler_sdk/cxx/mwarray.html
- Matlab与C/C++联合编程之Matlab以MEX方式调用C/C++代码(三)
- Matlab与C/C++联合编程之Matlab以MEX方式调用C/C++代码(二)
- Visual C++ 6.0与Matlab联合编程(1)---Matlab调用C++进行mex文件调试
- c++与matlab联合编程,调用Deploytool 生成exe文件和dll文件
- Matlab与C/C++联合编程之Matlab以MEX方式调用C/C++代码(四)
- Matlab与C/C++联合编程之Matlab以MEX方式调用C代码(五)完整过程加示
- Matlab与C/C++联合编程之Matlab以MEX方式调用C/C++代码(一)
- Matlab与C/C++联合编程之Matlab以MEX方式调用C代码(五)完整过程加示
- Matlab与C/C++联合编程之Matlab以MEX方式调用C/C++代码(二)
- Matlab与C/C++联合编程之Matlab以MEX方式调用C/C++代码(三)
- Matlab与C/C++联合编程之Matlab以MEX方式调用C/C++代码(三)
- Matlab与C/C++联合编程之Matlab以MEX方式调用C/C++代码(四)
- Matlab与C/C++联合编程之从Matlab调用C/C++代码
- Matlab与C/C++联合编程之Matlab以MEX方式调用C/C++代码(二)
- Matlab与C/C++联合编程之Matlab以MEX方式调用C/C++代码(一)
- Matlab与C/C++联合编程之Matlab以MEX方式调用C代码(五)完整过程加示
- Matlab与C/C++联合编程之Matlab以MEX方式调用C/C++代码(四)
- 【MATLAB与C的混合编程】之【C程序调用M文件编译后得到的DLL文件】
- MATLAB调用C/C++进行混合编程
- Matlab与C/C++联合编程之从Matlab…