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\n", 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\n", 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\n", chTmp);
}

 后面待補充結構體和cell數組的傳出,暫時還沒遇到這樣的需求。再貼上幾個參考網址:

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

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

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM