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

MATLAB调用C程序

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
3 @) Q- G9 F1 {- R4 b
通过把耗时长的函数用c语言实现,并编译成mex函数可以加快执行速度。; y, \, \( ~/ Z) x  _7 f7 e/ E) Q. d

- H5 _" o& _& ?7 _  n9 y. IMatlab本身是不带c语言的编译器的,所以要求你的机器上已经安装有VC,BC或Watcom C中的一种。
' b3 x; P& V, Z/ N: {, J3 f' ?4 S1 j1 G. G
如果你在安装Matlab时已经设置过编译器,那么现在你应该就可以使用mex命令来编译c语言的程序了。# {4 h. P- m9 c7 b' `. A
% q; x( B: X. o/ F8 S
如果当时没有选,就在Matlab里键入mex -setup,下面只要根据提示一步步设置就可以了。8 c& r! k  Y0 {/ ^/ A  O

  c7 ]- j1 ?7 V8 e% D6 r2 D+ A
& l5 q9 R1 H! E$ `& _0 ]8 T! f8 ]7 |3 B. m5 b0 x$ ]
为了测试你的路径设置正确与否,把下面的程序存为hello.c。- r& G- K5 Q0 Q
3 X% Q2 `9 @  K2 m( c. O* o7 o
?/ U4 d) N) w" i. N8 z
/*hello.c*/8 k  l( C9 \' B
#include "mex.h"* p) u+ ~* _7 N  {- e. B. n  J) ]
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
: f; J! `1 P% W% e4 a0 o{ mexPrintf("hello,world!/n");3 ]7 e. E. {4 A, h% M% F6 y
}
% B5 z5 H0 W& e) z$ a 假设你把hello.c放在了C:/TEST/下,在Matlab里用CD C:/TEST/ 将当前目录改为C:/ TEST/(注意,仅将C:/TEST/加入搜索路径是没有用的)。现在敲:' ], h% ^9 U6 D3 s  Z
mex hello.c 0 }% ]9 _) z$ l# }3 W% i2 s8 u9 f- W
如果一切顺利,编译应该在出现编译器提示信息后正常退出。如果你已将C:/TEST/加入了搜索路径,现在键入hello,程序会在屏幕上打出一行:
: y  Y7 K# j6 S- xhello,world! : Q, c/ K3 C/ C7 O* [1 }: u
+ b9 ?7 V. @6 Y% F, ?
整个程序由一个接口子过程 mexFunction构成。0 q$ n" n; z3 e# X  U) E& C
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) ; s$ J2 |/ E) |7 O
前面提到过,Matlab的mex函数有一定的接口规范,就是指这
( ^4 `; G8 |4 A: Bnlhs:输出参数数目 " p1 n6 M) I' p2 z1 [! {
plhs:指向输出参数的指针
) X4 @7 O, U8 c6 g' ?' Wnrhs:输入参数数目
- G$ a- V1 X' {. V& W& T' _例如,使用
. Q- J0 F9 P/ J# L8 F! }# R* {0 {[a,b]=test(c,d,e)' u% ]! W6 k( f5 ]
调用mex函数test时,传给test的这四个参数分别是4 N2 j5 Q$ m3 C9 B4 [0 I7 F# S) W# U
      2,plhs,3,prhs/ N2 |+ @' {8 N" g0 r
其中:
6 T, W1 L" p/ c7 Sprhs[0]=c : j. V8 O& w( U# D9 b2 z1 W1 }
prhs[1]=d
/ c: L; N: W& l, t% I0 K+ Y: Hprhs[2]=e 3 J. Y8 _" Q6 z. r3 |
当函数返回时,将会把你放在plhs[0],plhs[1]里的地址赋给a和b,达到返回数据的目的。  
: s) x( ^' @3 d' J& r细心的你也许已经注意到,prhs和plhs都是指向类型mxArray类型数据的指针。 这个类型是在mex.h中定义的,事实上,在Matlab里大多数数据都是以这种类型存在。当然还有其他的数据类型,可以参考Apiguide.pdf里的介绍。
: q* ?! G& P2 h/ G! i8 ^! }4 s# Q; W6 c6 J; o2 _! J
5 k+ D% ~8 t- ^' a
3 X+ }0 q$ N2 A" }' n8 t% `9 W  \
//hello.c 2.0 / {/ R* y; t/ w9 j8 Q& k- l# @
#include "mex.h" $ Q! Y" e8 K1 F
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) ) j5 P$ t7 K8 p- r" a6 d: k8 Z
{( B) T4 m3 ^) b: l
int i;
6 Z% t, R8 I/ T3 t1 i! mi=mxGetScalar(prhs[0]);
" f, g9 g) s' b' s. r( E) c" n% xif(i==1) 6 ?4 m7 `6 |7 x# X& {. V
  mexPrintf("hello,world!/n"); 5 x" G" i& M2 s  |
else ) \* [0 ?/ D  w0 A; F
  mexPrintf("大家好!/n");
: ~  F4 Y/ P+ \. V0 g) s}% U" l) A3 u6 U4 Y/ Z

) R2 M- \$ ^8 o
# z9 r5 i) t* t6 d) C2 F5 M$ k将这个程序编译通过后,执行hello(1),屏幕上会打出: hello,world! ; w0 `# B6 ?9 O/ l& q( e: o
而hello(0)将会得到: 大家好!% Y6 n  F/ @% Q& B

* E0 O& o, z  }7 h# y用到了一个函数:mxGetScalar,调用方式如下:
" d' u8 @: O: U5 K9 a% [  J   i=mxGetScalar(prhs[0]);
! A5 I; [( i0 |+ ~" E7 l" s; X8 ^"Scalar"就是标量的意思。在Matlab里数据都是以数组的形式存在的,mxGetScalar的作用就是把通过prhs[0]传递进来的mxArray类型的指针指向的数据(标量)赋给C程序里的变量。这个变量本来应该是double类型的,通过强制类型转换赋给了整形变量i。+ D5 n* G* _5 w$ a( s7 K+ ]
0 p# t! @: x: U* v" C  b

! w. ?9 {) I0 v8 {, s8 L6 q7 g3 P, I" a/ L* C
//hello.c 2.1
4 I; W3 {/ \5 H7 U+ c; X9 B#include "mex.h"
6 ?' P8 y& Q* {1 xvoid mexFunction(int nlhs, mxArray *plhs[], ) G* p; {6 M! g$ g: e- `
int nrhs, const mxArray *prhs[])
3 W* }% a4 }  s" D. S6 |' T{ 9 p' ?% P' }1 t+ ?; G
int *i;
6 u, r9 M. }" @$ P* S, li=mxGetPr(prhs[0]); - ~1 C  y2 A+ e4 f& \, |
if(i[0]==1)
% y. m( O2 `" t, O. V; i  mexPrintf("hello,world!/n"); ! I0 l  t' L  j+ b+ d# m
else 8 y0 U# u" n; I6 I8 `5 N' U
  mexPrintf("大家好!/n");
, r  r) O8 e) w$ ?! S} : U$ ^/ W/ Z) L  m+ s

* ^& a: o; o5 e; `% Z
( U) f3 ?, ]" e, u/ l5 i9 t! T; S+ P- Z9 O; d4 a( n) I; X1 I
这样,就通过mxGetPr函数从指向mxArray类型数据的prhs[0]获得了指向double类型的指针。" g! T8 Y( q- L% i: G% L
但是,还有个问题,如果输入的不是单个的数据,而是向量或矩阵,那该怎么处理呢 ?通过mxGetPr只能得到指向这个矩阵的指针,如果我们不知道这个矩阵的确切大小,就
4 r! `7 c: `% L; k5 @! |- ~没法对它进行计算。
  M$ b. T2 S7 Q) H为了解决这个问题,Matlab提供了两个函数mxGetM和mxGetN来获得传进来参数的行数 和列数。下面例程的功能很简单,就是获得输入的矩阵,把它在屏幕上显示出来: 3 J5 j3 Z' A3 d( F" s
% {) C' d* G) y: P8 _: F
/ _8 k7 e1 Z$ ?8 Z
//show.c 1.0
) e# L+ s# _0 ^6 {, B, l3 v  S5 f#include "mex.h" % c8 ~8 j- G8 o' Q- a3 [6 L
#include "mex.h" 9 D: h! h- a+ F2 a
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
6 ]- {0 x" b' V2 n7 k+ h5 g{ 0 o7 O$ V1 Z4 a$ k  R
double *data;
* M* @3 l% I) j! m4 Y9 ]( `% C8 Dint M,N; + B1 X# r- r" V5 @- m' a% M0 J; h
int i,j; + z) q5 P! l. N, R  r# P9 |
data=mxGetPr(prhs[0]); //获得指向矩阵的指针 9 ?* y$ Y# t5 p7 ]: O0 H
M=mxGetM(prhs[0]); //获得矩阵的行数
6 \( ~  u  e! t$ _N=mxGetN(prhs[0]); //获得矩阵的列数
( a3 n& `% g/ O( y+ nfor(i=0;i<M;i++) : J$ {+ s  t- W: O
{   for(j=0;j<N;j++)
- l9 `& q  a: f; B+ x+ b. _     mexPrintf("%4.3f  ",data[j*M+i]);
1 C* }: D% M4 u% u1 }1 k     mexPrintf("/n"); ( _3 \( G9 S' g9 r) i# R, C
  }
7 g9 F3 J4 r5 D$ w. d# B} ! f! q4 `1 I; u, Q
7 l2 n' O, V4 N: Q7 s

3 E. ^( \5 |( U5 M5 u8 l; J5 ~& ?0 {# S
编译完成后,用下面的命令测试一下: ( J% r8 k! u. Q/ B- X. }/ [
  a=1:10; ' G1 J0 I7 J) X$ p
  b=[a;a+1];
/ I: O1 G& B( c) V3 M  q+ z& z, I' _  show(a)
$ c' F* r$ e( b9 x/ E' `  V  show(b) % n0 w& p0 e9 h) L( R. @
需要注意的是,在Matlab里,矩阵第一行是从1开始的,而在C语言中,第一行的序数为零,Matlab里的矩阵元素b(i,j)在传递到C中的一维数组大data后对应于data[j*M+i] 。 4 m: [5 @; f$ ?+ h& |
输入数据是在函数调用之前已经在Matlab里申请了内存的,由于mex函数与Matlab共用同一个地址空间,因而在prhs[]里传递指针就可以达到参数传递的目的。但是,输出参数却需要在mex函数内申请到内存空间,才能将指针放在plhs[]中传递出去。由于返回指针类型必须是mxArray,所以Matlab专门提供了一个函数:mxCreateDoubleMatrix来实现内存的申请,函数原型如下:   k! Y# r0 _3 t, M
   mxArray *mxCreateDoubleMatrix(int m, int n, mxComplexity ComplexFlag) 8 t: N# g0 h# D: }; A" l& o8 u
   m:待申请矩阵的行数
' ~3 S6 S$ B( c) U* F& ?' ?7 R" N   n:待申请矩阵的列数 9 v! }; D, d* b& ~
为矩阵申请内存后,得到的是mxArray类型的指针,就可以放在plhs[]里传递回去了。但是对这个新矩阵的处理,却要在函数内完成,这时就需要用到前面介绍的mxGetPr。使用 mxGetPr获得指向这个矩阵中数据区的指针(double类型)后,就可以对这个矩阵进行各种操作和运算了。下面的程序是在上面的show.c的基础上稍作改变得到的,功能是将输  / L8 b- ~% @6 _7 M% I

3 ]3 S4 ~; y. F 9 t6 @" G% A( M7 H
5 Z" `6 G9 B) l% @" M, v
3 M8 X3 N/ {3 U( q% s$ I' E# s2 ~
//reverse.c 1.0 * Z. ^2 {* G- X. m; Z4 P& M
#include "mex.h"
" D) N  u8 Q( `- S! K4 ?void mexFunction(int nlhs, mxArray *plhs[],
1 F6 D  ?. \  s* \. B1 l# Q1 \& F    int nrhs, const mxArray *prhs[])
8 a7 S! i# M* n6 z! h{ ! D% b- B: Y5 Z" X
double *inData;
2 C# `& H  B' _4 \double *outData;
" H7 E) N  a( o/ s. Q( Yint M,N; , }: |  X% M" n: _: ]: G
int i,j; : [9 @: t6 d$ j  l
inData=mxGetPr(prhs[0]); 0 R8 f$ a# t) j1 V; H$ E( c
M=mxGetM(prhs[0]);
7 X( Q! ^4 Z3 CN=mxGetN(prhs[0]); - l5 H: X0 h5 c  D0 Y
plhs[0]=mxCreateDoubleMatrix(M,N,mxREAL);
$ g9 |& N0 k" B1 p1 c& B4 |7 O$ voutData=mxGetPr(plhs[0]);
! o. B0 h. @  H. w% _for(i=0;i<M;i++) ' O4 E# W/ t+ B
  for(j=0;j<N;j++) ' L; f( e. n7 g. i. t
   outData[j*M+i]=inData[(N-1-j)*M+i]; 6 M1 u, Y% |6 L: z& U* \
} # K# ~9 O; ]# ~2 n6 c. @, _
, \9 O9 t, h6 ?! D! U: ]# t
( ]5 E3 z, q) V8 y& o

1 l" i5 u$ m) N0 |当然,Matlab里使用到的并不是只有double类型这一种矩阵,还有字符串类型、稀疏矩阵、结构类型矩阵等等,并提供了相应的处理函数。本文用到编制mex程序中最经常遇到的一些函数,其余的详细情况清参考Apiref.pdf。
, ~5 T2 C0 y7 L6 t% W. c# B! @8 i2 T通过前面两部分的介绍,大家对参数的输入和输出方法应该有了基本的了解。具备了这些知识,就能够满足一般的编程需要了。但这些程序还有些小的缺陷,以前面介绍的re由于前面的例程中没有对输入、输出参数的数目及类型进行检查,导致程序的容错性很差,以下程序则容错性较好
7 N) l) Y2 r' e! x: C9 I- o4 l- l& G1 \& S. F

4 e! W" Z; p0 J: v, u3 ]7 x6 v#include "mex.h" / W5 t+ L3 g" O0 k, ?3 u
void mexFunction(int nlhs, mxArray *plhs[],  int nrhs, const mxArray *prhs[]) % u# w3 h1 k5 `: G6 K( q' W
{
0 Q0 {; P( j7 Z7 w, x! x9 {double *inData;
; G7 Y+ i) E+ b9 z, k& l+ f4 xdouble *outData;
5 F1 S+ ?& D: v: C9 Q% j- bint M,N; 0 u, z+ `- g" H( J$ `
//异常处理
5 @5 {3 y( w# p4 J* a1 P+ A//异常处理 + w$ V( j7 v4 I( Q
if(nrhs!=1)
! c. X$ ^  ?9 F/ v    mexErrMsgTxt("USAGE: b=reverse(a)/n"); : w$ v5 I! t/ A7 S* N& {* b1 `! \
  if(!mxIsDouble(prhs[0]))
' h) \5 y" c3 N  [8 P% M- f   mexErrMsgTxt("the Input Matrix must be double!/n"); 4 P. {  [5 B* V  F; y# B
   inData=mxGetPr(prhs[0]); ( i/ R  e3 F  c$ z
   M=mxGetM(prhs[0]);
0 X7 o3 s, J3 v8 B# r) p   N=mxGetN(prhs[0]);
& b9 l( U% \+ j   plhs[0]=mxCreateDoubleMatrix(M,N,mxREAL); # n& j: u- J; g& L
   outData=mxGetPr(plhs[0]); ( ]6 q4 a9 u7 z5 s0 |
   for(i=0;i<M;i++) # G% ]% y  n/ H* c/ K( N
     for(j=0;j<N;j++)
* @9 D* q- K/ c8 a     outData[j*M+i]=inData[(N-1-j)*M+i]; # z2 {4 L) ~# W
  } ) O8 z; _$ `6 U" X0 I) s. a

* U& Y. |+ c) o" x
. O9 w* i& U) f8 O4 X' m
  ?. }8 j1 {" T! W在上面的异常处理中,使用了两个新的函数:mexErrMsgTxt和mxIsDouble。MexErrMsgTxt在给出出错提示的同时退出当前程序的运行。MxIsDouble则用于判断mxArray中的数据是否double类型。当然Matlab还提供了许多用于判断其他数据类型的函数,这里不加详述。 % T& p) \: g6 t6 L) y/ n
需要说明的是,Matlab提供的API中,函数前缀有mex-和mx-两种。带mx-前缀的大多是对mxArray数据进行操作的函数,如mxIsDouble,mxCreateDoubleMatrix等等。而带mx前缀的则大多是与Matlab环境进行交互的函数,如mexPrintf,mxErrMsgTxt等等。了解了这一点,对在Apiref.pdf中查找所需的函数很有帮助。/ ^4 L6 g" F! N' I% |$ H  k
至此为止,使用C编写mex函数的基本过程已经介绍完了。 # _0 u7 C+ }* Q8 C
% ~8 y+ d9 N6 k. P* b- A' B, {

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-8-19 11:49 , Processed in 0.125000 second(s), 23 queries , Gzip On.

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

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

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