MATLAB擅長矩陣運算、原型驗證、可視化,但循環迭代性能弱(解釋執行)。C/C++擅長底層優化、硬件交互、現有代碼庫復用。MEX (MATLAB Executable) 打通兩者:在MATLAB中直接調用C/C++/Fortran函數,像調用內建函數一樣無縫傳遞數據。
一個MEX源文件包含兩部分:
mxArray數據。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)
}
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便於捕獲 |
// 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
mxCreateStructArray 定義字段名,逐字段mxSetField填充mxArray。mxCreateCellArray,mxSetCell 存入任意mxArray。mxCreateSparse,訪問 mxGetIr (行索引)、mxGetJc (列指針)、mxGetDoubles (值)。mxArray,可通過mxGetProperty/mxSetProperty訪問屬性,mexCallMATLAB調用方法。prhs:只讀,生命周期由MATLAB管理,**切勿修改、銷毀**。plhs:由mexFunction創建,所有權移交給MATLAB,**切勿手動mxDestroyArray**。mxArray:函數內創建用於中間計算,**必須mxDestroyArray釋放**,否則洩漏。malloc/new 分配,**必須在mexFunction返回前free/delete**,或註冊mexAtExit清理。持久化需用mexMakeMemoryPersistent(慎用)。mexCallMATLAB、mx*創建/訪問函數)於非主線程。mxGetDoubles等獲取),計算完成後寫回輸出mxArray。mex COMPFLAGS='$COMPFLAGS /openmp' timestwo.c (MSVC) 或 CFLAGS='$CFLAGS -fopenmp' (GCC/Clang)。現代MATLAB (R2019a+) 完整支持C++17。可使用std::vector、std::string、span、variant、模板元編程構建高質量計算核心,僅在邊界層轉換mxArray。
支持固定格式(.f)和自由格式(.f90)。入口為 subroutine mexFunction(nlhs, plhs, nrhs, prhs),參數為整數指針數組。數據訪問需用 mxGetPr 等C API,配合 ISO_C_BINDING 互操作。
matlab.exe,參數 -wait -r "dbstop if error; timestwo(2)",斷點調試。matlab -Dgdb 或 attach 進程。-fsanitize=address,undefined (GCC/Clang) 捕獲內存錯誤/UB。mexPrintf 輸出至MATLAB命令窗口,mexErrMsgIdAndTxt 拋出MATLAB捕獲異常。| 適用場景 | 不適用場景 |
|---|---|
| 熱點循環、遞歸、大數據遍歷性能瓶頸 | 原型驗證階段、邏輯頻繁變更 |
| 調用現有C/C++/Fortran庫 (BLAS, OpenCV, 自研算法) | 純矩陣運算 (MATLAB內建已高度優化並行) |
| 硬件交互 (DAQ, 串口, GPU內核啟動) | 簡單腳本、繪圖、文本處理 |
| 嵌入式代碼生成 (Simulink Coder/Embedded Coder) | 團隊缺乏C/C++經驗、維護成本過高 |
matlab::data::Array 現代C++封裝,支持matlab::engine::MATLABEngine 進程外調用。matlab.engine (Python調用MATLAB) 或 matlab.python (MATLAB調用Python)。