MATLAB使用mex调用C++ —— mexFunction函数及格式
网上关于这个函数如何编写如何使用写的非常杂乱,不断尝试才能碰巧成功。
淋过雨给大家撑把伞,把我在编写mex函数时遇到的坑和解决方式都罗列一下。
编写和运行步骤
- 一.准备工作及配置
- 二.mex函数格式及编写
- 三.在MATLAB中使用mex函数
一.准备工作及配置
1.安装MinGW-w64使用MEX调用C/C++
还没有做好准备工作的小伙伴可以去看我的这篇博客哈!
https://blog.csdn.net/Antoi_nette/article/details/137891285
2.VScode配置
使用的C++扩展:
- C/C++
- Code Runner
步骤: - 在vscode中按Ctrl+Shift+P输入
configuration
- 打开
c_cpp_properties.json
,在includePath
字段中添加待添加的SDK或者库的头文件路径。 - 具体路径是
matlab所在路径的/extern/include
。
注意:路径可能会被覆盖,具体原因我也不清楚,我的解决方法是删除了多余的扩展,并且加入了一段browse
。记得确保写了,
逗号。
"browse": {
"path": [
"F:/matlab/R2021b/extern/include"
],
"databaseFilename": ""
},
如图所示:
至此准备工作就差不多了!接下来就是主菜了!
二.mex函数格式及编写
编写mex函数主要分为两部分,一部分是mexFunction函数,一部分是主体函数。
- mexFunction函数的用处是进行matlab和C++的编译。
- 主体函数则是我们需要调用的C++函数。
在这里详细介绍一个坑(?)——那就是函数命名。
- CPP文件名自拟。
- mexFunction函数的名字不可更改。
- 主体函数名自拟。
CPP文件名和主体函数名可以不一致,但是最好保持一致,这样方便在matlab使用函数的时候不会搞错。
如果cpp文件名和主体函数名不一致,那么,在matlab中使用的是cpp文件名。
例如:
文件名叫
mex_function.cpp
,
mex_function.cpp
文件中包含了mexFunction(...)
函数和function(...)
主体函数。
那么,matlab命令为:mex mex_function.cpp
1.头文件
mexFunciton函数需要引用头文件:mex.h
和matrix.h
。
#include "mex.h"
#include "matrix.h"
其中,mex.h
是必须引用的,matrix.h
看需要,如果需要获取矩阵维度就需要引用这个头文件。这两个头文件都保存在1.2中提到的matlab所在路径的/extern/include
中。
直接都引用了得了,小孩子才做选择,大人allin。
2.mexFunction函数
mexFunction函数的格式如下,四个参数分别对应了matlab的左位输出和右位输入。
n代表数量,p代表指针,l/r代表左/右。
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]){
/**
* nlhs:函数左侧,输出参数数目
* plhs:函数左侧,指向输出参数的指针
* nrhs:函数右侧,输入参数数目
* prhs:函数右侧,指向输入参数的指针
*/
}
2.1.mexFunction函数输入编写
mexFunction函数是通过指针来指向输入输出矩阵的,因此我们需要在函数中定义指向指针并获取所需的数据。按需要设置指针的数量。
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]){
double *r,*t; //指向输入矩阵的指针
int nr,nt,k; //获取输入矩阵的维数
//创建指向输入矩阵r&t的指针,假设输入矩阵有两个。
r = mxGetPr(prhs[0]); //指向第一个输入矩阵r
t = mxGetPr(prhs[1]); //指向第二个输入矩阵t
//获取输入矩阵r的维数
nr = mxGetM(prhs[0]); //返回指定数组中的行数
k = mxGetN(prhs[0]); //返回指定数组中的列数
//获取输入矩阵t的维数
nt = mxGetM(prhs[1]);
//对矩阵t的列数进行判断
if(mxGetN(prhs[1])!=k){
mexErrMsgIdAndTxt( "MATLAB:dtw_c:dimNotMatch",
"dtw_c: Dimensions of input s and t must match.");
}
}
有人会问了,那nrhs和nlhs的作用是什么?
最简单的用处:判断输入参数是否正确的限制条件。
例如,如果我们输入参数有且只有2或3个,输出只有一个,那么就可以如下编写错误信息。
//invalid Case
if(nrhs!=2&&nrhs!=3){
mexErrMsgIdAndTxt( "MATLAB:dtw_c:invalidNumInputs",
"Two or three inputs required.");
}
if(nlhs>1){
mexErrMsgIdAndTxt( "MATLAB:dtw_c:invalidNumOutputs",
"对应function名字: One output required.");
}
这样就可以帮助我们快速找到错误信息和对应的函数名字(如果存在多个函数)。
2.3.mexFunction函数主体编写
一般来说,直接使用主体函数就行,将主体函数分开写有利于代码修改。主体函数就按需正常编写就可以了。
如果只有一个结果,可以直接定义输出指针(参考2.4.case1)指向结果。
如果有多个结果,可以定义一个结构体或者什么都行,存储,然后挨个赋值给plhs。
例如:
// 调用主体函数function
Result result = function(...); //定义结构体存储多个输出
2.4.mexFunction函数输出编写
输出和输入类似。创建一个指针指向输出然后存放。不同的是,我们需要定义每一个参数的行列数。
例如:
//定义plhs[0]存放的结果; 参数1-行数, 参数2-列数。
//case1:假设此处存放简单的double类型。
plhs[0] = mxCreateDoubleMatrix( 1, 1, mxREAL);
//创建指向plhs[0]矩阵的指针
double *dp0 = mxGetPr(plhs[0]);
//结果赋值
dp0[0] = function(...);
//case2: 假设此处存放一个vector<double>数据。
//获取数据的行数
int row = result.size();//假设result是主体函数的结果
//定义plhs[1]存放的结果; 参数1-行数, 参数2-列数。
plhs[1] = mxCreateDoubleMatrix(Size, 1, mxREAL);
//创建指向plhs[1]矩阵的指针
double *dp1 = mxGetPr(plhs[1]);
for (int i = 0; i < row; ++i) {
dp1[i] = result[i];
}
还有更多输出就以此类推。
三.在MATLAB中使用mex函数
指令:mex CPP文件名
然后就可以直接使用了!
over!庆祝!