C/C++與Matlab混合程式設計初探

bendanban發表於2014-07-15

==================================================================

% 歡迎轉載,尊重原創,所以轉載請註明出處。

% http://blog.csdn.net/bendanban/article/details/37830495

=======================分割線以下為正文================================


     Matlab 擁有豐富的功能,程式設計簡單。不過,有些情況下,Matlab程式的執行速度比較慢。C/C++編譯執行的程式速度比較快,程式設計難度上比Matlab要高一些。因此存在一種方案,就是使用Matlab實現我們的實驗程式,用C/C++來實現Matlab程式中比較耗時的部分,從Matlab程式中呼叫C/C++的程式以實現加速。

     本文主要講解如何在Matlab中呼叫C/C++的程式,以及如何編寫可供Matlab程式呼叫的C/C++程式。

     本文主要分以下幾部分:

     Hello Matlab,用一個簡單的例子來說明如何在Matlab中呼叫C/C++的程式,以及可供Matlab呼叫的C/C++程式應該注意哪些基本事項。

     Matlab呼叫C/C++程式傳遞引數。討論在C/C++中是如何使用Matlab傳來的引數的。

     Matlab與C/C++混合程式設計的方法論。給出在一般情況下使用Matlab與C/C++混合程式設計的方法步驟,讓大家有一個較為清晰的應用此技術的思路。

     關於資料儲存的說明。說明資料在Matlab中的儲存方式。

     注意:本文認為讀者會使用Matlab,掌握C/C++語言,並且有一臺計算機。計算機上安裝有Windows的作業系統,作業系統上裝有Matlab以及Visual Studio(比如VS2008,VS2010等)。或者計算機上安裝有Linux的作業系統,系統上裝有Matlab,GCC。


hello Matlab

     我們一步步完成一個叫“Hello Matlab”的程式。

     第一步:在你的計算機D盤下,建立一個目錄命名為HiMat。在D:\HiMat目錄下建立一個文字檔案,命名為“abhimat.cpp”。將Code 1中的程式碼拷貝到“abhimat.cpp”檔案中,儲存。(注意,這裡建立目錄以及命名等行為不是規定的,只是為了講解方便)。

#include "mex.h"
void mexFunction (int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
  mexPrintf("hello matlab in C/CPP.\n");
}
Code 1, abhimat.cpp

     “abhimat.cpp”就是將要在Matlab中被呼叫的C/C++程式碼。

     第二步:在Matlab中編譯“abhimat.cpp”。啟動Matlab,進入D:\HiMat目錄,在Matlab命令視窗中執行code 2中的命令,根據提示完成C/C++編譯環境的配置。注意:如果你有多個編譯器,建議選擇最新的。

mex -setup
Code 2, 設定Matlab的C/C++編譯環境

     完成配置後,在Matlab中執行Code 3的命令來編譯abhimat.cpp。

mex abhimat.cpp
Code 3, 編譯abhimat.cpp

    第三步:執行編譯後的C/C++程式。在Matlab命令視窗輸入“abhimat”或者”abhimat()”,都可以呼叫編譯後的程式,推薦使用後者。

     細心的讀者已經注意到了:

  • 在Matlab中呼叫的C/C++函式名就是編譯後以mex*(這裡,*表示任意多個字元,例如mexw64)為字尾名的檔名。
  • Matlab執行abhimat()命令後,實際執行的是mexFunction函式中的程式。

Matlab呼叫C/C++程式傳遞引數


    此節我們討論下,在供Matlab呼叫的C/C++程式中,我們是如何知道Matlab呼叫的引數型別、個數的。

    給出Matlab中呼叫C/C++程式的一個例項,如code 4所示。

c = [1 2;3 4;5 6];
d = [1 1;1 1;1 1];
[a, b] = abfunc(c, d);
Code 4, Matlab呼叫C/C++程式例項

    下面的工作是如何在當前目錄下一個命名為abfunc.cpp的檔案中實現mexFunction函式。在這個函式中如何獲得Matlab命令中的c、d兩個變數的值,如何返回a、b兩個變數呢。

    注意mexFunction函式中的四個引數,一一作出說明:

    nlhs:mexFunction的第一個引數,它指示Matlab的呼叫命令中等號左側有幾個變數。例如,code 4中的呼叫,nlhs的值為2,因為它的等號左側有兩個變數,他們是a和b。

    plhs: mexFunction的第二個引數,它指示Matlab的呼叫命令中等號左側變數的指標。例如,code 4中的呼叫,plhs[0]表示的是a,plhs[1]表示的是b。

    nrhs:mexFunction的第三個引數,它指示Matlab的呼叫命令中等號右側的變數個數。例如,code 4中的呼叫,nrhs的值為2,因為它的等號右側有兩個變數,他們是c和d。

    prhs:mexFunction的第四個引數,它指示Matlab呼叫命令中等號右側的變數指標。例如,code 4中的呼叫,prhs[0]表示的是c,prhs[1]表示的是d。

    mxArrary是一個不可見的資料型別,是Matlab定義的,大家只需要知道mxArrary的指標與Matlab中的變數一一對應就可以了。

    下面實現abfunc.cpp,功能是a=c+d; b = c-d;具體程式碼如code 5所示。

#include "mex.h"
void mexFunction (int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
  double *p_c, *p_d;
  double *p_a, *p_b;

  int c_rows, c_cols;
  int d_rows, d_cols;
  
  int numEl;
  int n;
  
  mxAssert(nlhs==2 && nrhs==2, "Error: number of variables");

  c_rows = mxGetM(prhs[0]);// get rows of c
  c_cols = mxGetN(prhs[0]);// get cols of c
  d_rows = mxGetM(prhs[1]);// get rows of d
  d_cols = mxGetN(prhs[1]);// get cols of d

  mxAssert(c_rows==d_rows && c_cols==d_cols, "Error: cols and rows");

  // create output buffer
  plhs[0] = mxCreateDoubleMatrix(c_rows, c_cols, mxREAL);
  plhs[1] = mxCreateDoubleMatrix(c_rows, c_cols, mxREAL);

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

  // compute a = c + d; b = c - d;
  numEl = c_rows*c_cols;
  for (n = 0; n < numEl; n++)
  {
    p_a[n] = p_c[n] + p_d[n];
    p_b[n] = p_c[n] - p_d[n];
  }
}
Code 5,  abfunc.cpp的實現

    說明一下code 5中用到的函式。這些函式大都以mx開頭。mxAssert是斷言,類似於C\C++中的assert。mxGetM獲得Matlab傳來的變數的行數,mxGetN獲得Matlab傳來的變數的列數。mxCreateDoubleMatrix建立一個2維的Matlab變數,形參分別用於指定變數的行數、列數、元素型別(mxREAL表示實數,mxCOMPLEX表示複數)。mxGetData用於獲得記憶體中資料塊的首地址。

    編譯並測試Code 5中的程式碼,參見Code 6。

mex abfunc.cpp
c = [1 2;3 4;5 6];
d = [1 1;1 1;1 1];
[a, b] = abfunc(c, d);
Code 6, Code5的測試程式碼

    Code 6的輸出結果如下:

a =
     2     3
     4     5
     6     7
b =
     0     1
     2     3
     4     5



關於資料儲存的說明

   Matlab中的資料是按列儲存的。例如,a=[1,2;3,4;5,6],a的資料在記憶體中的儲存順序是:1、3、5、2、4、6。在C\C++中使用Matlab傳來的變數時,一定要注意資料的儲存順序


Matlab與C/C++混合程式設計的方法論

鑑於@程式設計小手 的建議,新增一個關於使用此方法的方法論流程圖。希望它能讓各位明白在什麼情況下可是使用這種混合程式設計的技術、如何一步步實現。參見圖1的流程圖:

圖 1、Matlab與C/C++混編方法論流程圖

另附:文中程式碼下載位置: http://download.csdn.net/detail/bendanban/7643701


相關文章