找回密码
 注册
关于网站域名变更的通知
查看: 445|回复: 1
打印 上一主题 下一主题

MATLAB调用C程序

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2020-5-27 16:09 | 只看该作者 回帖奖励 |正序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
9 |  U: X% ^" t+ x, I
通过把耗时长的函数用c语言实现,并编译成mex函数可以加快执行速度。$ R/ \* I$ b5 T% ?2 X- z

4 ^+ s7 R1 F( _/ ^; L% d3 TMatlab本身是不带c语言的编译器的,所以要求你的机器上已经安装有VC,BC或Watcom C中的一种。
7 j4 H" a6 J& V+ y  ?" h2 {. q7 P3 b; l2 d; Z) w5 `
如果你在安装Matlab时已经设置过编译器,那么现在你应该就可以使用mex命令来编译c语言的程序了。* n) N) H0 P# A3 y0 \, a2 [
1 ?3 }4 B- \, [: P6 t" n
如果当时没有选,就在Matlab里键入mex -setup,下面只要根据提示一步步设置就可以了。5 d, C7 l4 c* Z6 X* u

7 \! V2 C: a) V. C. z1 z! ?+ \& Y7 v
; _9 v" m5 _4 r4 ?/ k$ A
' W9 [0 K8 |; W4 w+ Q* `5 s8 s4 T: }为了测试你的路径设置正确与否,把下面的程序存为hello.c。
) @; X; H& c7 f+ w% q2 _/ b, d9 f/ h( x4 O% t% O* O6 A
?  q7 m5 d7 b, v! ]/ k
/*hello.c*/
0 g9 K5 |0 i2 q4 k7 W1 U- t( `#include "mex.h"
. N# }; k! h% Y7 Z( q) rvoid mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])) B" z/ a6 w- S9 x) P# A
{ mexPrintf("hello,world!/n");! C7 f: f1 \6 y3 y' V/ |
}
- c0 j2 x9 _/ b  u7 P6 d 假设你把hello.c放在了C:/TEST/下,在Matlab里用CD C:/TEST/ 将当前目录改为C:/ TEST/(注意,仅将C:/TEST/加入搜索路径是没有用的)。现在敲:
7 n8 Q; Z" I, n" |8 H3 xmex hello.c
) }+ l: B% [+ E如果一切顺利,编译应该在出现编译器提示信息后正常退出。如果你已将C:/TEST/加入了搜索路径,现在键入hello,程序会在屏幕上打出一行:
6 `  @+ h$ W* [9 C: H) g/ i* s5 Yhello,world! 9 R, z% P  B9 }
3 E) g+ S/ Q% H$ D* l
整个程序由一个接口子过程 mexFunction构成。) ~1 z2 W! L+ a1 i2 e  k
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) % V4 R  [4 ]4 O' ~5 X# B! Y9 P- l
前面提到过,Matlab的mex函数有一定的接口规范,就是指这6 K1 B$ n! S9 F; U! r
nlhs:输出参数数目 ! L" X- ]" k6 Y* O7 `- w
plhs:指向输出参数的指针 ; Y. S) M7 K! q$ W- D# V9 L
nrhs:输入参数数目 % x) g4 n9 H, Z* p/ H
例如,使用
. P* {4 Y4 Z9 M* N[a,b]=test(c,d,e)
8 |1 v, ]0 s' a调用mex函数test时,传给test的这四个参数分别是
" C9 o7 N9 \& |" |2 T% J2 I      2,plhs,3,prhs
1 M8 ~, e+ J; d  C) ?" ~5 K. O其中: 9 ^3 }. n1 o# Q% Y' ?6 H
prhs[0]=c
; _" z  [# ^% I: L' pprhs[1]=d 6 B1 p' E5 C% V
prhs[2]=e 8 y. j% C5 R% e4 P" ]! k% D
当函数返回时,将会把你放在plhs[0],plhs[1]里的地址赋给a和b,达到返回数据的目的。  - q) S$ _7 a( j
细心的你也许已经注意到,prhs和plhs都是指向类型mxArray类型数据的指针。 这个类型是在mex.h中定义的,事实上,在Matlab里大多数数据都是以这种类型存在。当然还有其他的数据类型,可以参考Apiguide.pdf里的介绍。
+ s* e( k3 E7 p) W' _% y7 C" b3 r5 l9 w- X9 C* @% f/ r
( g0 Z; M, j8 M; C* d/ }  i

6 a/ X* r5 Q: [" }* @3 `//hello.c 2.0 : |2 _8 t. \1 F; v3 A) \
#include "mex.h" / H: S# k  E! ~& a9 b+ u& j
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) . Z  A; ^+ Q. ~$ L: x2 ^; i
{; k4 h4 j/ i) D- U7 t9 G7 i
int i;   y9 c9 R% A2 b* e/ K
i=mxGetScalar(prhs[0]);
4 Q8 B7 ^) R* c, e5 Iif(i==1)
8 h1 n8 P8 J+ a1 l- j* }1 I' [  mexPrintf("hello,world!/n"); ( Q  F0 f- S9 g; T$ U
else 5 ^4 c, j& [% M9 Y
  mexPrintf("大家好!/n"); / U: R; u% X- `
}
0 m1 Z, Y* L8 Q  j3 y
4 R% W7 F0 v; }2 E+ j1 M( d- h/ J# K. d9 f! g! A2 }
将这个程序编译通过后,执行hello(1),屏幕上会打出: hello,world! # w  _) b0 t+ X" A/ U
而hello(0)将会得到: 大家好!
7 B1 f( E- R, `8 y) R5 _+ D
( S/ A. u, Q- G! w& E% g用到了一个函数:mxGetScalar,调用方式如下:
( W" U9 J$ ^; t: Q( s4 G   i=mxGetScalar(prhs[0]); . Y8 P' C: n9 }) ~
"Scalar"就是标量的意思。在Matlab里数据都是以数组的形式存在的,mxGetScalar的作用就是把通过prhs[0]传递进来的mxArray类型的指针指向的数据(标量)赋给C程序里的变量。这个变量本来应该是double类型的,通过强制类型转换赋给了整形变量i。
2 ^# t) \& u6 S' j) E1 E  p0 R2 Q1 E$ V
, @0 @3 {6 u/ l7 G
+ o' Z; G7 ?' U- ]0 v/ b
//hello.c 2.1
$ |6 c$ T9 J" e: {! [#include "mex.h"
3 I: {, R" e5 xvoid mexFunction(int nlhs, mxArray *plhs[], & N3 n% a, O/ H* s9 n) h# M6 D
int nrhs, const mxArray *prhs[])
  o5 z! s$ v* I- E8 E9 u! r{
1 l) M; f3 }! m! e0 j$ yint *i;
0 }  T* w+ H' Y9 l7 `  _+ s3 ti=mxGetPr(prhs[0]);
5 g7 V" g! ]0 C2 k- ~6 Eif(i[0]==1) * ?- u0 F+ R" U* ^" e' f
  mexPrintf("hello,world!/n"); 9 @" I/ }) W) [5 a" Q  N
else
* D* S7 s9 d% l5 s8 i4 P1 L2 o  mexPrintf("大家好!/n");
9 P  F% C0 s0 n$ B+ |* I4 R' ~}
- B: v0 c9 h6 O- I. y
6 ]- l: p9 v% [5 m6 \5 M* d
. n$ _3 y; \) q) ]
, Z, C$ A( o- `0 }这样,就通过mxGetPr函数从指向mxArray类型数据的prhs[0]获得了指向double类型的指针。
. B: h2 t  D  b& I$ V! E% Z( y2 I# \但是,还有个问题,如果输入的不是单个的数据,而是向量或矩阵,那该怎么处理呢 ?通过mxGetPr只能得到指向这个矩阵的指针,如果我们不知道这个矩阵的确切大小,就 1 H) q+ J8 D/ u  z1 `, J8 e
没法对它进行计算。 8 l; Z1 B* n# H! M  T% I: {
为了解决这个问题,Matlab提供了两个函数mxGetM和mxGetN来获得传进来参数的行数 和列数。下面例程的功能很简单,就是获得输入的矩阵,把它在屏幕上显示出来:
) ?# A! U2 ?1 N, R0 R
2 `1 C, J/ w& [. y7 D. W+ X. }/ W# D  p' w/ }' j4 Q9 M
//show.c 1.0 + V& J8 v. I6 Y9 G2 ]
#include "mex.h" % d2 A# c1 e; U8 \7 m# I0 }. h
#include "mex.h" # m2 F6 i' C0 c4 ^6 F1 s
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
) b; R2 Q3 W3 X2 H{ 7 w, Z$ I8 V+ d0 m+ p" z! i3 k' C9 i
double *data;
  J" q, c( ^6 H* v1 O! Y6 mint M,N; 8 ~) \; g! b  U1 S( N' r; D  x
int i,j; 0 s* _( d* P! ?
data=mxGetPr(prhs[0]); //获得指向矩阵的指针
- S! T9 I* ^+ t# p4 e$ EM=mxGetM(prhs[0]); //获得矩阵的行数 ! B# M/ w4 d5 e0 S( N
N=mxGetN(prhs[0]); //获得矩阵的列数 - J: f# d6 _) r! z
for(i=0;i<M;i++)
4 ~9 `8 w0 o% ^# r5 v0 N' p8 o{   for(j=0;j<N;j++)
) E# ]2 ?. T/ r     mexPrintf("%4.3f  ",data[j*M+i]);
( x# |) U7 N1 X" F1 o  ?$ G% O     mexPrintf("/n"); 7 }4 @/ ^$ M( j
  }) a3 d% S3 s3 L* u
}
) U3 D- u* a( H  y( o! e* \1 \& k1 f9 v- V' x# c7 r0 v+ D1 ^
8 C0 Q& q0 k* ]8 _9 p1 L
7 D2 O8 c% B4 `* T; Z
编译完成后,用下面的命令测试一下:
2 C& h' W8 b( U- K. q  a=1:10; # ?" y; `+ s7 U
  b=[a;a+1];
% |; I' S8 g' Q. l3 N$ S; x" M  show(a)
% \8 r% `! d  l; V  show(b) ( J& q) L% w. }! H
需要注意的是,在Matlab里,矩阵第一行是从1开始的,而在C语言中,第一行的序数为零,Matlab里的矩阵元素b(i,j)在传递到C中的一维数组大data后对应于data[j*M+i] 。 ( l$ f6 u. V$ `
输入数据是在函数调用之前已经在Matlab里申请了内存的,由于mex函数与Matlab共用同一个地址空间,因而在prhs[]里传递指针就可以达到参数传递的目的。但是,输出参数却需要在mex函数内申请到内存空间,才能将指针放在plhs[]中传递出去。由于返回指针类型必须是mxArray,所以Matlab专门提供了一个函数:mxCreateDoubleMatrix来实现内存的申请,函数原型如下:
) ]+ }) I" |: @0 |, n6 o% d0 O# \   mxArray *mxCreateDoubleMatrix(int m, int n, mxComplexity ComplexFlag)   R) j: O( I! J3 U/ W/ u
   m:待申请矩阵的行数 " S# }; G6 A$ j. D1 h3 r3 P
   n:待申请矩阵的列数 8 X/ h1 I& k4 E" C- p/ K+ J
为矩阵申请内存后,得到的是mxArray类型的指针,就可以放在plhs[]里传递回去了。但是对这个新矩阵的处理,却要在函数内完成,这时就需要用到前面介绍的mxGetPr。使用 mxGetPr获得指向这个矩阵中数据区的指针(double类型)后,就可以对这个矩阵进行各种操作和运算了。下面的程序是在上面的show.c的基础上稍作改变得到的,功能是将输  , U7 O; o- G( J# {" X  q) M, b9 v
" Z' y) d' d" |- g# f7 x( X

( Y" r4 j/ ~, E& b/ K3 @1 ?
0 Q( g7 i/ l9 k9 P' e3 a0 x4 |& }5 W1 ]( }2 v1 H. r7 X4 s
//reverse.c 1.0
  V: i7 N2 u" u' M4 c6 }#include "mex.h" 9 J- P6 O7 [5 Y# k
void mexFunction(int nlhs, mxArray *plhs[],
1 N$ i$ P2 a: B8 I4 K) `; o* @    int nrhs, const mxArray *prhs[])
, [$ S/ m: |. S) e) E& Y. R9 ]8 F{ 4 X2 x! W7 X! N; Y0 v7 P
double *inData;
; Z* a2 X; C6 n. S$ Ndouble *outData;
2 m. Q3 u6 z- K3 h" ~2 A1 Vint M,N;
. q* l8 p( l5 c- A4 Fint i,j;
. n: e! }# q4 r1 U: XinData=mxGetPr(prhs[0]); ! f. G3 e& P% Q7 y- a" F& @
M=mxGetM(prhs[0]); ) Z  Q7 y1 s  c, T8 m0 |/ n
N=mxGetN(prhs[0]);
% p% b6 U) Z8 Vplhs[0]=mxCreateDoubleMatrix(M,N,mxREAL); $ m, i( n8 A+ ^. r+ g: F
outData=mxGetPr(plhs[0]); " r/ h: c& ^" [
for(i=0;i<M;i++)
; Q( u. ^& V0 \  for(j=0;j<N;j++)
; Y* S+ v6 b1 s* ~9 C   outData[j*M+i]=inData[(N-1-j)*M+i];
: j+ T& A/ Q$ S  b' Z6 R( i- j}
2 u2 [" J3 h! [
6 q# y! H8 O$ q  H2 ~
4 |' X  b; R; k. s+ B2 E/ }: r
& T) I7 a- n7 o6 f2 s+ P  T当然,Matlab里使用到的并不是只有double类型这一种矩阵,还有字符串类型、稀疏矩阵、结构类型矩阵等等,并提供了相应的处理函数。本文用到编制mex程序中最经常遇到的一些函数,其余的详细情况清参考Apiref.pdf。 & x7 ?: L2 C5 i+ S- q  U7 v$ `
通过前面两部分的介绍,大家对参数的输入和输出方法应该有了基本的了解。具备了这些知识,就能够满足一般的编程需要了。但这些程序还有些小的缺陷,以前面介绍的re由于前面的例程中没有对输入、输出参数的数目及类型进行检查,导致程序的容错性很差,以下程序则容错性较好
( R& C- X  G+ O; r) X- p8 u: k% v  Q8 x- H3 @6 s

% c- n5 ?6 t+ [7 m- {$ }  I#include "mex.h" # |4 L) }- K2 z8 j; k9 I
void mexFunction(int nlhs, mxArray *plhs[],  int nrhs, const mxArray *prhs[])
6 w; I; I6 ]: n4 c; B! B{   l6 }% x' `* e2 p% H) M
double *inData; : W6 r+ f$ H1 F+ Y
double *outData;   z3 x0 ]( K* p8 P, K
int M,N;
# w1 E" {; A+ l+ ?//异常处理 ( i3 N! a7 `3 `% C  X3 w- R: ]  U: y6 p
//异常处理 - F1 O$ {7 J/ s# v5 C9 x& a& H
if(nrhs!=1)
0 F/ H) e$ M; H% M: W8 f( E4 P    mexErrMsgTxt("USAGE: b=reverse(a)/n");
, L5 ^/ Y, L0 N7 v+ F  if(!mxIsDouble(prhs[0]))
/ \& g$ y7 j! x: s   mexErrMsgTxt("the Input Matrix must be double!/n");
, `8 r8 g0 ?+ w, o   inData=mxGetPr(prhs[0]);
: H6 m/ @' d  p" @% D   M=mxGetM(prhs[0]);
4 H$ N6 K/ l" Y5 n5 U   N=mxGetN(prhs[0]);
& A: A  G( a( K9 N7 |   plhs[0]=mxCreateDoubleMatrix(M,N,mxREAL);
! a0 |4 ?. e: ^   outData=mxGetPr(plhs[0]); : o8 v' B# C% w. u( y) n
   for(i=0;i<M;i++)
, l! l& i5 L9 `+ }+ L  j- _     for(j=0;j<N;j++)
, C$ [6 V  Z, z/ z7 ~7 [     outData[j*M+i]=inData[(N-1-j)*M+i];
1 [/ U& O* C# X& r3 c0 O! E  } ) c$ ?9 I# U; r9 Y2 c! h

( M( K1 b$ l0 O 2 F& t, g: \( {7 D! T
* {3 ?% d# J( {% R' m3 n: e' ~' n
在上面的异常处理中,使用了两个新的函数:mexErrMsgTxt和mxIsDouble。MexErrMsgTxt在给出出错提示的同时退出当前程序的运行。MxIsDouble则用于判断mxArray中的数据是否double类型。当然Matlab还提供了许多用于判断其他数据类型的函数,这里不加详述。 7 V& ]* |; H. I/ c. k9 d5 {% ]
需要说明的是,Matlab提供的API中,函数前缀有mex-和mx-两种。带mx-前缀的大多是对mxArray数据进行操作的函数,如mxIsDouble,mxCreateDoubleMatrix等等。而带mx前缀的则大多是与Matlab环境进行交互的函数,如mexPrintf,mxErrMsgTxt等等。了解了这一点,对在Apiref.pdf中查找所需的函数很有帮助。
' S( T# d  }" {& l至此为止,使用C编写mex函数的基本过程已经介绍完了。
) ]$ t6 T3 c! l. r/ M5 d
% G. R( t0 d" K& e( L) E

该用户从未签到

2#
发表于 2020-5-27 17:04 | 只看该作者
MATLAB调用C程序
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-11-24 12:17 , Processed in 0.171875 second(s), 24 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表