您的位置:首页 > 编程语言 > MATLAB

matlab调用c++函数

2017-01-17 10:59 531 查看
经常会遇到一个问题,就是怎么用matlab来调用已经写好的c++代码,下面就学习一下。

首先要明白调用c代码,需要用到MEX,他主要和matlab的主要接口,接口的主要入口为如下函数:

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
nlhs:输出参数数目   (Left-handside)
plhs:指向输出参数的指针
nrhs:输入参数数目
举个例子:
[a,b]=test(c,d,e)
调用mex函数test时,传给test的这三个参数分别是 prhs[0]=c ,prhs[1]=d ,prhs[2]=e
当函数返回时,将会把你放在plhs[0],plhs[1]里的地址赋给a和b,达到返回数据的目的。

上述中mxArrray为matlab的数据格式,是指针,需要注意一点都额是,matlab中,举证是按列优先在存储,c++中是按行优先来存储,比如a=[1,2;3,4;5,6],a的数据在内存中的存储顺序是:1、3、5、2、4、6。在C\C++中使用Matlab传来的变量时,一定要注意数据的存储顺序

这个函数就类似C中的main()函数,所有的接口都会从这个mexFunction中来实现。下面举个例子

1. 我们需要执行一个矩阵的加法(本来在matlab执行起来更加高效,此处仅为了教学说明),比如在c++的文件名是addFun.cpp,我们希望在matlab中做如下调用:

a = [1,2,3;4,5,6];
b = [6,5,4;3,2,1];
c = a+b
c_add = addFun(a,b)
2.下面开始addFun.cpp函数的编写:

//每个matlab接口必须包含的头文件,有些函数如:mxCreateDoubleMatrix在该文件中声明
#include<mex.h>

// Do CHECK and throw a Mex error if check fails
inline void mxCHECK(bool expr, const char* msg) {
if(!expr) {
mexErrMsgTxt(msg);
}
}
//mexFunction是每个matlab接口函数必须的一个入口函数(可以没有,但没有也就每声明意义了。),可以理解为c,c++中的main函数,其中参数,返回值也是固定的。形参int nlhs, mxArray **plhs, int nrhs, const mxArray **prhs分别代表:返回参数个数,返回参数,输入参数个数,输入参数。其中的mxGetM(),mxGetData()等函数我们在下面的工程分析中予以解释。
void mexFunction(int nlhs, mxArray **plhs, int nrhs, const mxArray **prhs) {
mxCHECK(nrhs==2, "Error:must input 2 matrix for add");

int a_rows = mxGetM(prhs[0]);// get rows of a
int a_cols = mxGetN(prhs[0]);// get cols of a
int b_rows = mxGetM(prhs[1]);// get rows of b
int b_cols = mxGetN(prhs[1]);// get cols of b
mxCHECK(a_rows==a_rows && b_cols==b_cols, "Error: cols and rows of two input matrix must same");

// create output buffer
plhs[0] = mxCreateDoubleMatrix(a_rows, a_cols, mxREAL);

// get buffer pointers
double *p_c = (double*)mxGetData(plhs[0]);
double *p_a = (double*)mxGetData(prhs[0]);
double *p_b = (double*)mxGetData(prhs[1]);

// compute c = a + b;
int numEl = a_rows*a_cols;
for (int i = 0; i < numEl; i++) {
p_c[i] = p_a[i] + p_b[i];
}
}
3.做好上面的工作后,我们在matlab命令行中进行编译:

mex addFun.cpp
得到类似addFun.mexa64的文件,这时我们就可以像开始一样进行调用了(比如a=addFun(b,c))。(有的版本的matlab还需要对mex进行设置,请参考mex setup)

如果有多个函数接口,该如何写呢?

如下主要参考:http://blog.csdn.net/sunnyxiaohu/article/details/51506359

首先要经过三步骤:

第一,申明接口

#define MEX_ARGS int nlhs, mxArray **plhs, int nrhs, const mxArray **prhs
//1,定义几个我们需要在matlab中调用的函数
// Usage: caffe_('version')
static void version(MEX_ARGS) {
mxCHECK(nrhs == 0, "Usage: caffe_('version')");
// Return version string
plhs[0] = mxCreateString(AS_STRING(CAFFE_VERSION));
}
static void get_solver(MEX_ARGS) {
//.......
}


第二,注册

//2.我们期望处理多个函数时,能像命令行一样,给一个命令,就能让他执行某个函数,于是我们定义下面的结构体,其中func是一个函数指针指向参数为MEX_ARGS,返回值为void的函数。
struct handler_registry {
string cmd;
void (*func)(MEX_ARGS);
};
//2.将上面定义的这些函数进行一些简单的注册,方便后面mexFunction函数中进行调用
static handler_registry handlers[] = {
// Public API functions
{ "get_solver",         get_solver      },
//.......
{ "version",            version         },
// The end.
{ "END",                NULL            },
};

第三,mxFunction中实现

// Usage: caffe_(api_command, arg1, arg2, ...)
void mexFunction(MEX_ARGS) {
mexLock();  // Avoid clearing the mex file.
mxCHECK(nrhs > 0, "Usage: caffe_(api_command, arg1, arg2, ...)");
// Handle input command
char* cmd = mxArrayToString(prhs[0]);
bool dispatched = false;
// Dispatch to cmd handler
for (int i = 0; handlers[i].func != NULL; i++) {
if (handlers[i].cmd.compare(cmd) == 0) {
handlers[i].func(nlhs, plhs, nrhs-1, prhs+1);
dispatched = true;
break;
}
}
if (!dispatched) {
ostringstream error_msg;
error_msg << "Unknown command '" << cmd << "'";
mxERROR(error_msg.str().c_str());
}
mxFree(cmd);
}

完成上述三部后,就可以在matlab中:
就只需要简单的如caffe_('verion')进行调用了,是不是设计的感觉还不错呢
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: