Ada kalanya MATLAB mentok: satu loop panas yang tidak bisa di-vectorize, pustaka C warisan proyek lama yang tidak boleh ditulis ulang, atau driver perangkat yang hanya tersedia dalam C. Untuk tiga situasi tersebut MATLAB menyediakan MEX — MATLAB Executable — yakni fungsi C/C++ yang dikompilasi menjadi berkas pustaka dan dipanggil persis seperti fungsi MATLAB biasa. Chapter ini membedah gerbang mexFunction, tipe data mxArray, kompilasi mex, dan alternatif loadlibrary untuk memanggil shared library C tanpa menulis MEX. Cakupan materinya:
- struktur gateway
mexFunctionbaris-per-baris pada contoh klasiktimestwo.c - tipe data
mxArray,mxCreateDoubleMatrix,mxGetPr, dan typed data API modern - validasi galat dengan
mexErrMsgIdAndTxt - kompilasi
mex timestwo.cdan kompatibilitas API klasik vs modern - alternatif
loadlibrary+calllibuntuk shared library C
Kapan Perlu Integrasi C #
Aturannya: C adalah pilihan terakhir setelah dua jalan MATLAB murni — vectorization dan parfor — gagal memberi kecepatan yang dibutuhkan. Mekanismenya: MEX file berjalan di thread yang sama dengan MATLAB sehingga panggilan per elemen dari C tidak membayar interpreter overhead. Tabel berikut memetakan situasi ke solusinya:
| Situasi | Solusi pertama | Solusi lanjutan |
|---|---|---|
| loop panas per elemen | vectorization | MEX C dengan for array |
| butuh paralelisme data | parfor | MEX + OpenMP |
| pakai pustaka C yang sudah ada | loadlibrary + calllib | MEX wrapper |
| akses perangkat/driver C | — | MEX langsung ke driver |
Anatomi Gateway mexFunction #
Aturannya: setiap MEX file C wajib punya tepat satu fungsi mexFunction — gateway yang dipanggil MATLAB setiap kali pengguna memanggil nama berkas. Mekanismenya: MATLAB meneruskan seluruh argumen masukan dan keluaran lewat empat parameter, dan kode C kita yang bertugas memvalidasi, menyalin data, memanggil rutin komputasi, lalu mengisi keluaran. Bentuk umumnya:
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])Empat parameter tersebut adalah kontrak antara MATLAB dan C: nlhs dan nrhs menghitung jumlah argumen keluaran (left-hand side) dan masukan (right-hand side), plhs adalah array penampung keluaran yang harus kita isi, dan prhs adalah array argumen masukan bertipe mxArray *. Contoh klasik dari dokumentasi MathWorks, timestwo.c, mengalikan satu skalar dengan dua — berkas lengkapnya tersedia sebagai Berkas Sumber chapter ini:
#include "mex.h"
void timestwo(double y[], double x[])
{
y[0] = 2.0 * x[0];
}
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
double *x, *y;
size_t m, n;
/* Periksa jumlah argumen masukan dan keluaran. */
if (nrhs != 1) {
mexErrMsgIdAndTxt("MATLAB:timestwo:invalidNumInputs",
"One input required.");
} else if (nlhs > 1) {
mexErrMsgIdAndTxt("MATLAB:timestwo:maxlhs",
"Too many output arguments.");
}
/* Masukan harus berupa skalar double nonkompleks. */
m = mxGetM(prhs[0]);
n = mxGetN(prhs[0]);
if (!mxIsDouble(prhs[0]) || mxIsComplex(prhs[0]) ||
(m != 1) || (n != 1)) {
mexErrMsgIdAndTxt("MATLAB:timestwo:inputNotScalar",
"Input must be a noncomplex scalar double.");
}
/* Buat matriks keluaran (padanan zeros di sisi MATLAB). */
plhs[0] = mxCreateDoubleMatrix(m, n, mxREAL);
/* Ambil pointer ke data nyata pada masukan dan keluaran. */
x = mxGetPr(prhs[0]);
y = mxGetPr(plhs[0]);
/* Panggil rutin komputasi timestwo. */
timestwo(y, x);
}Mari kita bedah baris-baris kode di atas:
- Baris 1 (
#include "mex.h"): header resmi MEX API — tanpa baris ini, fungsimx*danmex*tidak dikenal compiler. - Baris 3-6 (
void timestwo(double y[], double x[])): rutin komputasi murni C — logika inti dipisah dari gateway agar mudah diuji di C. - Baris 8-9 (
void mexFunction(int nlhs, mxArray *plhs[], ...)): gateway — MATLAB memanggil fungsi ini, bukantimestwolangsung. - Baris 14-21 (
if (nrhs != 1) ... else if (nlhs > 1)): validasi jumlah argumen;mexErrMsgIdAndTxtmelempar galat ber-identifier ke MATLAB dan menghentikan eksekusi MEX saat itu juga. - Baris 23-30 (
mxGetM ... inputNotScalar): validasi tipe dan ukuran masukan — skalardoublenonkompleks saja; kombinasimxIsDouble,mxIsComplex,m,nmenolakchar,logical, kompleks, dan matriks. - Baris 33 (
plhs[0] = mxCreateDoubleMatrix(m, n, mxREAL)): alokasi matriks keluaranmxREAL(data nyata, tanpa bagian imajiner) — padananzeros(m,n). - Baris 36-37 (
x = mxGetPr(prhs[0]); y = mxGetPr(plhs[0]);):mxGetPrmengembalikandouble*yang menunjuk data numerikmxArray— C bekerja pada memori MATLAB secara langsung. - Baris 40 (
timestwo(y, x)): rutin komputasi dipanggil; hasil tertulis ke memori keluaran.
mxArray: Jembatan Data MATLAB-C #
Aturannya: seluruh data yang melintasi batas MATLAB-C berupa mxArray — tipe opaque yang membungkus array MATLAB beserta tipenya. Mekanismenya: fungsi mx dipakai untuk membaca struktur (ukuran, tipe) dan mengambil pointer ke datanya; dua API tersedia — API klasik dan typed data API R2018a+:
| Tipe data MATLAB | Membuat (mxArray) | Akses klasik | Akses modern (R2018a+) |
|---|---|---|---|
double nyata | mxCreateDoubleMatrix | mxGetPr / mxSetPr | mxGetDoubles / mxSetDoubles |
double kompleks | mxCreateDoubleMatrix + mxCOMPLEX | mxGetPr + mxGetPi | mxGetComplexDoubles |
numerik lain (int32, single, …) | mxCreateNumericMatrix | mxGetData | mxGetInt32s, mxGetSingles, … |
char | mxCreateString | mxGetChars / mxGetString | sama dengan klasik |
Pada API modern, baris x = mxGetPr(prhs[0]); ditulis menjadi:
mxDouble *x = mxGetDoubles(prhs[0]); /* R2018a+ typed data API */Tipe mxDouble dijamin double presisi penuh, dan API ini juga satu-satunya jalur bersih untuk data kompleks ter-interleave. Untuk kode baru, MathWorks menganjurkan typed data API; contoh timestwo.c di atas tetap memakai mxGetPr karena pola klasik ini masih dikompilasi dan paling banyak dipakai di kode warisan.
Kompilasi dan Kompatibilitas API #
Aturannya: perintah mex mengubah timestwo.c menjadi pustaka binaan lokal — timestwo.mexa64 di Linux, timestwo.mexw64 di Windows, timestwo.maci64 di macOS — yang dipanggil dari MATLAB dengan timestwo(21). Mekanismenya: mex memanggil compiler C/C++ yang terpasang, menautkan pustaka MATLAB, lalu menghasilkan berkas dengan ekstensi platform. Urutan pengerjaannya:
mex -setup c % sekali saja: pilih compiler C
mex timestwo.c % kompilasi menjadi timestwo.mexa64/dll
timestwo(21) % panggil seperti fungsi MATLAB biasaKompatibilitas API dikendalikan flag -R2017b (API klasik, kompleks terpisah — default lama untuk MEX C) dan -R2018a (API ter-interleave + typed data — standar untuk MEX C++ dan kode baru). Kode real-data seperti timestwo.c dikompilasi benar pada kedua API; tulis flag secara eksplisit (mex -R2018a timestwo.c) bila kode memakai mxGetDoubles dan sejenisnya. Panggilan timestwo(21) lalu mengembalikan hasil sesuai dokumentasi resmi:
ans =
42Pemanggilan dengan masukan salah — misalnya timestwo('21') — menghentikan eksekusi dan mencetak galat Error using timestwo disusul pesan Input must be a noncomplex scalar double.; perilaku tersebut berasal dari panggilan mexErrMsgIdAndTxt pada gateway.
Alternatif: loadlibrary dan calllib #
Aturannya: bila target berupa shared library C (.dll/.so/.dylib) yang sudah ada beserta header-nya, kita tidak perlu menulis MEX sama sekali. Mekanismenya: loadlibrary memuat pustaka ke memori MATLAB, calllib memanggil satu fungsi C dengan konversi argumen otomatis, dan unloadlibrary melepasnya:
loadlibrary('libkonversi', 'konversi.h') % muat pustaka + header
hasil = calllib('libkonversi', 'hitungDiskon', 100000) % panggil fungsi C
unloadlibrary('libkonversi') % lepaskan dari memoriFungsi C yang bisa dipanggil dibatasi pada tipe primitif dan pointer yang bisa dipetakan ke tipe MATLAB — double* masuk-keluar sebagai argumen pointer bertipe lib.pointer. Dibandingkan MEX, rute ini lebih cepat ditulis karena tidak ada kode C baru; batasnya fleksibilitas: MEX tetap diperlukan bila kita butuh kontrol penuh atas mxArray. Panggilan loadlibrary/calllib adalah fitur MATLAB — runner Octave tidak mengujinya.
Menguji Logika timestwo di MATLAB Murni #
Karena kompilasi MEX tidak tersedia di runner, contoh.m menguji semantik timestwo.c di MATLAB murni: fungsi timestwo di dalamnya memvalidasi masukan dengan aturan yang sama (isa menggantikan mxIsDouble, isreal menggantikan mxIsComplex, isscalar menggantikan cek m/n), lalu melempar galat ber-identifier yang sama:
daftarUji = { ...
'double skalar', 21, true; ...
'double negatif', -3.5, true; ...
'nol', 0, true; ...
'char ''21''', '21', false; ...
'double kompleks', 2+3i, false; ...
'logical', true, false; ...
'matriks 1x2', [1 2], false ...
};
for k = 1:size(daftarUji, 1)
label = daftarUji{k, 1};
nilai = daftarUji{k, 2};
harusSukses = daftarUji{k, 3};
try
y = timestwo(nilai);
status = sprintf('OK (y = %g)', y);
sukses = true;
catch err
status = sprintf('galat %s', err.identifier);
sukses = false;
end
assert(isequal(sukses, harusSukses), 'uji "%s" gagal', label);
fprintf('%-18s -> %s\n', label, status);
endBagian ketiga contoh.m membandingkan loop ala C dengan operasi vektoris — menegaskan alasan klasik menulis MEX sekaligus idiom MATLAB yang menggantikannya:
x = 1:8;
y = zeros(size(x)); % padanan mxCreateDoubleMatrix + mxGetPr
for k = 1:numel(x)
y(k) = 2 * x(k); % padanan y[k] = 2.0 * x[k]
end
fprintf('loop C-style vs 2*x: identik = %d\n', isequal(y, 2*x));Output yang Dihasilkan (keseluruhan contoh.m):
== Bagian 1: hitung y = 2*x ==
timestwo(21) = 42
timestwo(-3.5) = -7
timestwo(0) = 0
timestwo(1e+10) = 2e+10
== Bagian 2: kontrak argumen gateway ==
double skalar -> OK (y = 42)
double negatif -> OK (y = -7)
nol -> OK (y = 0)
char '21' -> galat MATLAB:timestwo:inputNotScalar
double kompleks -> galat MATLAB:timestwo:inputNotScalar
logical -> galat MATLAB:timestwo:inputNotScalar
matriks 1x2 -> galat MATLAB:timestwo:inputNotScalar
== Bagian 3: loop C vs vektoris ==
loop C-style vs 2*x: identik = 1
kontrak & logika timestwo: 12 uji lulus, PASSTujuh baris kontrak tersebut adalah tabel kebenaran gateway versi MATLAB: hanya skalar double nonkompleks yang lolos, lima masukan lain ditolak dengan identifier MATLAB:timestwo:inputNotScalar — persis cabang galat pada kode C.
Ringkasan #
MEX menghubungkan MATLAB dan C lewat satu gateway mexFunction(nlhs, plhs, nrhs, prhs): validasi argumen lebih dulu (mxIsDouble, mxIsComplex, ukuran), lalu alokasi keluaran (mxCreateDoubleMatrix), pengambilan pointer (mxGetPr, atau mxGetDoubles di API R2018a+), dan pemanggilan rutin komputasi; galat validasi dilempar lewat mexErrMsgIdAndTxt. Kompilasi mex timestwo.c menghasilkan pustaka platform (.mexa64/.mexw64), sedangkan loadlibrary+calllib menjadi jalur tanpa-MEX untuk shared library yang sudah ada. Skrip contoh.m membuktikan kontrak dan logika times-two di MATLAB murni: 12 uji lulus termasuk lima cabang galat, dan loop C-style terbukti identik dengan 2*x.
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
timestwo.c
Unduh berkas/*=====================================================================
* timestwo.c - contoh klasik dari dokumentasi MathWorks
*
* Mengalikan satu masukan skalar dengan 2.
*
* Kompilasi (MATLAB dengan C compiler terpasang):
* mex timestwo.c
*
* Lalu panggil dari Command Window:
* timestwo(21) -> 42
*
* Sumber: MathWorks, "Tables of MEX Function Source Code Examples"
* https://www.mathworks.com/help/matlab/matlab_external/
* table-of-mex-source-code-examples.html
*===================================================================*/
#include "mex.h"
void timestwo(double y[], double x[])
{
y[0] = 2.0 * x[0];
}
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
double *x, *y;
size_t m, n;
/* Periksa jumlah argumen masukan dan keluaran. */
if (nrhs != 1) {
mexErrMsgIdAndTxt("MATLAB:timestwo:invalidNumInputs",
"One input required.");
} else if (nlhs > 1) {
mexErrMsgIdAndTxt("MATLAB:timestwo:maxlhs",
"Too many output arguments.");
}
/* Masukan harus berupa skalar double nonkompleks. */
m = mxGetM(prhs[0]);
n = mxGetN(prhs[0]);
if (!mxIsDouble(prhs[0]) || mxIsComplex(prhs[0]) ||
(m != 1) || (n != 1)) {
mexErrMsgIdAndTxt("MATLAB:timestwo:inputNotScalar",
"Input must be a noncomplex scalar double.");
}
/* Buat matriks keluaran (padanan zeros di sisi MATLAB). */
plhs[0] = mxCreateDoubleMatrix(m, n, mxREAL);
/* Ambil pointer ke data nyata pada masukan dan keluaran. */
x = mxGetPr(prhs[0]);
y = mxGetPr(plhs[0]);
/* Panggil rutin komputasi timestwo. */
timestwo(y, x);
}