• 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

     

  • 相关阅读:
    HTC G7 搜索和感光按键修改
    Delphi开源组件SynEdit
    (转)Delphi获取windows系统版本信息
    TDateTime转UTC的时间差
    Windows7 C盘无法读写文件
    Convert UTC string to TDatetime in Delphi
    delphi抓全屏图,游戏窗口,游戏Client窗口
    ADO Table Locate
    Delphi与管道操作
    Delphi从UTC (GMT)返回时差
  • 原文地址:https://www.cnblogs.com/Key-Ky/p/4233581.html
Copyright © 2020-2023  润新知