首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

MATLAB與C語言混合編程:MEX接口深度解析與實戰

     編輯:關於C語言

為什麼需要MEX?

MATLAB擅長矩陣運算、原型驗證、可視化,但循環迭代性能弱(解釋執行)。C/C++擅長底層優化、硬件交互、現有代碼庫復用。MEX (MATLAB Executable) 打通兩者:在MATLAB中直接調用C/C++/Fortran函數,像調用內建函數一樣無縫傳遞數據。

MEX文件架構

一個MEX源文件包含兩部分:

  1. 計算程序:純C/C++邏輯,處理mxArray數據。
  2. 入口函數 mexFunction:固定簽名,負責參數檢查、mxArray與C類型轉換、調用計算程序、構建返回值。
#include "mex.h"
#include "matrix.h" // 可選,matrix.h 已被 mex.h 包含

void mexFunction(int nlhs, mxArray *plhs[],
                 int nrhs, const mxArray *prhs[]) {
    // nlhs: 輸出參數個數 (left-hand side)
    // plhs: 輸出參數 mxArray 指針數組
    // nrhs: 輸入參數個數 (right-hand side)
    // prhs: 輸入參數 mxArray 指針數組 (const)
}

核心API:mxArray 數據訪問

mxArray 是MATLAB所有數據類型的統一容器。關鍵訪問函數:

任務API備註
獲取類型/屬性mxGetClassID, mxIsDouble, mxIsComplex, mxIsSparse, mxGetNumberOfDimensions, mxGetDimensions
獲取數據指針(數值)mxGetDoubles, mxGetSingles, mxGetInt8s... (C Matrix API, R2018a+)推薦,類型安全。舊版用mxGetPr/mxGetPi (double*)
獲取數據指針(邏輯/字符)mxGetLogicals, mxGetChars (R2018a+)
創建數值矩陣mxCreateDoubleMatrix(m,n,mxREAL), mxCreateNumericArray, mxCreateNumericMatrix支持任意維度、類型
創建字符串mxCreateString, mxCreateCharArray
創建結構體/元胞數組mxCreateStructArray, mxCreateCellArray
設置字段/元胞mxSetField, mxSetCell
拷貝數據mxCopyPtrToReal8, memcpy (配合新API指針)
錯誤報告mexErrMsgIdAndTxt, mexWarnMsgIdAndTxt帶ID便於捕獲

完整實例:標量乘2 (timestwo)

// timestwo.c
#include "mex.h"

void timestwo(double *y, const double *x) {
    *y = 2.0 * *x;
}

void mexFunction(int nlhs, mxArray *plhs[],
                 int nrhs, const mxArray *prhs[]) {
    // 1. 參數檢查
    if (nrhs != 1) mexErrMsgIdAndTxt("MATLAB:timestwo:rhs", "需要1個輸入。");
    if (nlhs > 1)  mexErrMsgIdAndTxt("MATLAB:timestwo:lhs", "最多1個輸出。");
    if (!mxIsDouble(prhs[0]) || mxIsComplex(prhs[0]) || 
        mxGetNumberOfElements(prhs[0]) != 1) {
        mexErrMsgIdAndTxt("MATLAB:timestwo:input", "輸入必須為實標量。");
    }

    // 2. 創建輸出矩陣 (1x1 double)
    plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL);

    // 3. 獲取數據指針 (R2018a+ API)
    double *x = mxGetDoubles(prhs[0]);
    double *y = mxGetDoubles(plhs[0]);

    // 4. 調用計算核心
    timestwo(y, x);
}

編譯與調用

> mex timestwo.c
Building with 'Microsoft Visual C++ 2022'.
MEX completed successfully.
>> x = 2; y = timestwo(x)
y = 4

進階主題

1. 複雜數據結構傳遞

  • 結構體:mxCreateStructArray 定義字段名,逐字段mxSetField填充mxArray。
  • 元胞數組:mxCreateCellArray,mxSetCell 存入任意mxArray。
  • 稀疏矩陣:mxCreateSparse,訪問 mxGetIr (行索引)、mxGetJc (列指針)、mxGetDoubles (值)。
  • 對象/類:MATLAB類實例也是mxArray,可通過mxGetProperty/mxSetProperty訪問屬性,mexCallMATLAB調用方法。

2. 內存管理與生命周期

  • 輸入prhs:只讀,生命周期由MATLAB管理,**切勿修改、銷毀**。
  • 輸出plhs:由mexFunction創建,所有權移交給MATLAB,**切勿手動mxDestroyArray**。
  • 臨時mxArray:函數內創建用於中間計算,**必須mxDestroyArray釋放**,否則洩漏。
  • C/C++堆內存:malloc/new 分配,**必須在mexFunction返回前free/delete**,或註冊mexAtExit清理。持久化需用mexMakeMemoryPersistent(慎用)。

3. 多線程與並行計算

  • MEX函數默認在MATLAB主線程運行。**不支持直接調用MATLAB API**(mexCallMATLAB、mx*創建/訪問函數)於非主線程。
  • 計算密集型核心可使用 OpenMP、TBB、std::thread 並行,**僅傳入原始數據指針**(mxGetDoubles等獲取),計算完成後寫回輸出mxArray。
  • 編譯需添加標誌:mex COMPFLAGS='$COMPFLAGS /openmp' timestwo.c (MSVC) 或 CFLAGS='$CFLAGS -fopenmp' (GCC/Clang)。

4. C++11/14/17/20 支持

現代MATLAB (R2019a+) 完整支持C++17。可使用std::vector、std::string、span、variant、模板元編程構建高質量計算核心,僅在邊界層轉換mxArray。

5. Fortran MEX

支持固定格式(.f)和自由格式(.f90)。入口為 subroutine mexFunction(nlhs, plhs, nrhs, prhs),參數為整數指針數組。數據訪問需用 mxGetPr 等C API,配合 ISO_C_BINDING 互操作。

調試技巧

  • Visual Studio:項目屬性→調試→命令設置為 matlab.exe,參數 -wait -r "dbstop if error; timestwo(2)",斷點調試。
  • GDB/LLDB:matlab -Dgdb 或 attach 進程。
  • Sanitizers:編譯加 -fsanitize=address,undefined (GCC/Clang) 捕獲內存錯誤/UB。
  • 日誌:mexPrintf 輸出至MATLAB命令窗口,mexErrMsgIdAndTxt 拋出MATLAB捕獲異常。

何時使用/不使用 MEX

適用場景不適用場景
熱點循環、遞歸、大數據遍歷性能瓶頸原型驗證階段、邏輯頻繁變更
調用現有C/C++/Fortran庫 (BLAS, OpenCV, 自研算法)純矩陣運算 (MATLAB內建已高度優化並行)
硬件交互 (DAQ, 串口, GPU內核啟動)簡單腳本、繪圖、文本處理
嵌入式代碼生成 (Simulink Coder/Embedded Coder)團隊缺乏C/C++經驗、維護成本過高

現代替代方案

  • MATLAB Coder:將MATLAB代碼自動生成C/C++代碼/MEX/庫/可執行文件,支持子集語言。
  • C++ MATLAB Data API (R2017b+):matlab::data::Array 現代C++封裝,支持matlab::engine::MATLABEngine 進程外調用。
  • Python調用:matlab.engine (Python調用MATLAB) 或 matlab.python (MATLAB調用Python)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved