zoukankan      html  css  js  c++  java
  • matlab和C/C++混合编程--Mex

      最近的项目需要matlab和C的混合编程,经过一番努力终于完成了项目要解决的问题。现在就将Mex的一些经验总结一下,当然只是刚刚开始,以后随着学习的深入继续添加。首先讲讲写Mex的一些常规规定,然后我们会重点关注混合编程中最难解决数据的问题--结构到底如何转换,并且后面会重点说一下自己的程序。

    一、Mex的结构

    先看一个简单的程序(该程序保存在matlab主目录下名字是mexDemon.cpp,或者在主目录下新建一个.cpp文件):

    #include "mex.h"  
    //加入头文件,该头文件在VS2010中无法include,但是不影响其在matlab中的编译,反而在matlab编译还需要include它
    #include <vector>
    using namespace std;
    
    void mexFunction(int nlhs, mxArray *plhs[],int nrhs,const mxArray *prhs[]) 
    //mexFunction就类似于main函数
    {
        //nlhs代表的是输出参数的个数
        //plhs是一个指针数组,里面的指针指向mxArray类型,每一个指针指向一个输出
        //nrhs代表的是输入参数的个数
        //prhs是一个指针数组,里面的指针指向mxArray类型,每一个指针指向一个输入
    
      vector<vector<double> > array2d;
        double *z;
        plhs[0] = mxCreateDoubleMatrix( 5, 6, mxREAL);//第一个输出是一个5*6的矩阵
        z = mxGetPr(plhs[0]);//获得矩阵的第一个元素的指针
        array2d.resize(5);
        int ii = 0;
        for(int i = 0; i < 5; i++){
            for(int j = 0; j < 6; j++){
                z[i*6 + j] = ii; //指针访问矩阵是列优先的,请自己循环程序和分析输出结果
                ii++;
            }
        }
    }  
    
    /*
     *ans =
    
         0     5    10    15    20    25
         1     6    11    16    21    26
         2     7    12    17    22    27
         3     8    13    18    23    28
         4     9    14    19    24    29
     */

    然后对Matlab编译应用程序mex的编译器进行设置,在命令窗口输入 Mex –setup。 然后跟着步骤走选择合适的编译器即可。

    设置完编译器之后在命令窗口输入Mex mexDemon.cpp 进行编译生成.mexw64文件,生成之后便可以直接调用了,例如本例子可以这样调用,就是直接在命令窗口输入 a = mexDemon(); 返回值如上。


     二、C和Matlab的数据结构的转换

    (1)数值的传递

    matlab -> c++

    x = mxGetScalar(prhs[0]);//该函数获取matlab传递过来的数值;
    

     c++ -> matlab

    plhs[0] = mxCreateDoubleMatrix(1,1,mxREAL);//创建返回的矩阵,范围plhs[0]为mxArray类型
    y = mxGetPr(plhs[0]);//获取返回plhs[0]的数据地址,其后可以修改y的值就可以返回了

    一个实例(numDemon.cpp):

    #include "mex.h"
    
    void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]){
        int x = mxGetScalar(prhs[0]); //将第一个输入参数转为Scalar标量,也就是单数值
        printf("%d
    ", x); //打印
        
        double *y; 
        plhs[0] = mxCreateDoubleMatrix(1,1,mxREAL); //让第一个输出参数指向一个1*1的矩阵
        y = mxGetPr(plhs[0]); //获得矩阵的第一个元素的指针
        *y = 10; //将其赋值为10
    }
    

     如下图在命令窗口编译:


     (2)矩阵的传入与传出

    关于传出(c++到Matlab, 就是第一个例子),下面可以再给一个例子是如何从matlab传入到c++,看下面这段代码:

    #include "mex.h"
    
    void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]){
        double *dataCursor;
        vector<vector<double> > parms;
    
        dataCursor = mxGetPr(prhs[0]); //得到输入矩阵的第一个元素的指针
        int mrows = mxGetM(prhs[0]);   //获得矩阵的行
        int ncols = mxGetN(prhs[0]);   //获得矩阵的列
        printf("%d_%d
    ", mrows, ncols);  //打印行和列
        
        parms.resize(mrows);  //初始化
        for(int i = 0; i < mrows; i++){
            parms[i].resize(ncols);
        }
    
        for(int i = 0; i < mrows; i++){
            for(int j = 0; j < ncols; j++){
                parms[i][j] = dataCursor[j * mrows + i]; //拷贝矩阵的元素到vector of vector
            }
        }
    
    }
    

     同样在命令窗口编译即可。


    (3)字符串的传入与传出

    matlab -> c++ (传入)

    char *input_buf;
    input_buf = mxArrayToString(prhs[0]);//使用mxArrayToString将mxArray转换为c、c++字符串
    

     c++ -> matlab (传出)

    char *output_buf;//定义字符串缓存
    size_t buflen = (mxGetM(prhs[0]) * mxGetN(prhs[0])) + 1;//获取字符串长度,mxGetM获取行数,mxGetN获取列数
    output_buf=mxCalloc(buflen, sizeof(char));//使用mxCalloc分配输出字符串数组
    plhs[0] = mxCreateString(output_buf);//使用mxCreateString创建mxArray输出
    mxfree(output_buf);
    

     一个实例(strDemon.cpp)

    #include "mex.h"
    void revord(char *input_buf, size_t buflen, char *output_buf)
    {
      mwSize i;
      if (buflen == 0) return;
     
      for(i=0;i<buflen-1;i++)
        *(output_buf+i) = *(input_buf+buflen-i-2);
    }
    
    void mexFunction( int nlhs, mxArray *plhs[],
                      int nrhs, const mxArray *prhs[])
    {
        char *input_buf, *output_buf;
        size_t buflen;
       
        buflen = (mxGetM(prhs[0]) * mxGetN(prhs[0])) + 1; //因为本程序是翻转字符串,所以输入输出字符串的长度应该一样
       
        output_buf=mxCalloc(buflen, sizeof(char)); //申请空间
       
        input_buf = mxArrayToString(prhs[0]); //获得输入字符串
       
        revord(input_buf, buflen, output_buf); //翻转字符串
       
        plhs[0] = mxCreateString(output_buf); 
        mxFree(input_buf);
        return;
    }
    

    同样编译一下即可。 


    (4)cell的传入

    #include "mex.h"
    
    void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]){
    	mwSize cellNdim = mxGetNumberOfDimensions(prhs[0]); //这里介绍两个函数mxGetNumberOfDimensions和mxGetDimensions
    	const int *cellColPtr = mxGetDimensions(prhs[0]);
    	//mxGetDimensions: 就是返回一个指针ptr,每一个指针所指向的值是每一个维度的元素个数。例如有矩阵3*2的矩阵,那么*(ptr)为3,*(ptr+1)为2.
    	//mxGetNumberOfDimensions: 返回mxArray的维度。
     	int cellNRow = *(label_dims);
        int cellNCol = *(label_dims + 1);
    
        mxArray *ptr;
        ptr = mxGetCell(prhs[0], 0); //获取cell的第0个元素,返回一个mxArray指针,第二个参数代表cell中元素的下标
    
        mxArray *cellOfCell;
        cellOfCell = mxGetCell(ptr, 0);    //当然cell里面可以还是cell,那么应该再样写
    
        mxArray *cellOfStr;
        char *chTmp;
        cellOfStr = mxGetCell(prhs[0], 0); //当然cell里面可以是字符串
        chTmp = mxArrayToString(cellOfStr);
        printf("%s
    ", chTmp);
    }
    

     后面待补充结构体和cell数组的传出,暂时还没遇到这样的需求。再贴上几个参考网址:

    1.http://blog.sina.com.cn/s/blog_9db9f81901013yv2.html

    2.http://blog.sina.com.cn/s/blog_80202a090100uhup.html

     

  • 相关阅读:
    【Codeforces 349B】Color the Fence
    【Codeforces 459D】Pashmak and Parmida's problem
    【Codeforces 467C】George and Job
    【Codeforces 161D】Distance in Tree
    【Codeforces 522A】Reposts
    【Codeforces 225C】Barcode
    【Codeforces 446A】DZY Loves Sequences
    【Codeforces 429B】Working out
    【Codeforces 478C】Table Decorations
    【Codeforces 478C】Table Decorations
  • 原文地址:https://www.cnblogs.com/Key-Ky/p/4233581.html
Copyright © 2011-2022 走看看