matlab调用c++函数

经常会遇到一个问题,就是怎么用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')进行调用了,是不是设计的感觉还不错呢



展开阅读全文

没有更多推荐了,返回首页