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

MATLAB调用C程序

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
6 J8 O' l, v: O1 a( d$ O. X
通过把耗时长的函数用c语言实现,并编译成mex函数可以加快执行速度。7 s6 M( p! `( I# E2 _( p& ^

$ d* }' C2 m; W# O  @Matlab本身是不带c语言的编译器的,所以要求你的机器上已经安装有VC,BC或Watcom C中的一种。
8 r' R- L/ q+ J. ^
4 q% I2 \: D4 H6 l2 x3 P如果你在安装Matlab时已经设置过编译器,那么现在你应该就可以使用mex命令来编译c语言的程序了。: R8 a% W6 c& T
4 E3 B* X7 e, X9 z# ^+ t
如果当时没有选,就在Matlab里键入mex -setup,下面只要根据提示一步步设置就可以了。
5 u! V) G; f' t- w, P  G8 x4 E
  r5 ~1 C' E; |* R% d. ^ / f, q0 o' X% ]
) F1 \( v3 W; w" u
为了测试你的路径设置正确与否,把下面的程序存为hello.c。, f" O7 Y) A$ g7 T7 Q- z" m
" e& u  j& J  k6 v8 X& X
?5 \" _9 {0 i7 Z5 w4 m6 s: b
/*hello.c*/
- l; K( ~- N( v: c. L' m, G4 n#include "mex.h"0 T3 V, X2 f: S- s% U
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])0 R# w: x0 F) M" n% ]9 w
{ mexPrintf("hello,world!/n");
  b2 l8 ~6 s; S. U9 C}
; f; b& ^, t# e0 G% {2 N$ J 假设你把hello.c放在了C:/TEST/下,在Matlab里用CD C:/TEST/ 将当前目录改为C:/ TEST/(注意,仅将C:/TEST/加入搜索路径是没有用的)。现在敲:6 K9 h' s# J$ X% b7 K8 a! M, O' x
mex hello.c
/ j" B9 \. o0 H7 q9 T如果一切顺利,编译应该在出现编译器提示信息后正常退出。如果你已将C:/TEST/加入了搜索路径,现在键入hello,程序会在屏幕上打出一行:
, X9 S: _' X1 D9 u# }. `+ }hello,world!
& H4 @! N) q" J
* f# M/ V" O# y9 k整个程序由一个接口子过程 mexFunction构成。
! F# z# N. f& Z  yvoid mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) : }( x3 O0 Y8 D! ^$ N
前面提到过,Matlab的mex函数有一定的接口规范,就是指这
4 q0 d! u, P/ n! ], pnlhs:输出参数数目
; z$ T6 A& G# S, Z1 Q+ d& T1 Zplhs:指向输出参数的指针
% e$ Q) s/ m( p( j& J; e, n9 Z6 bnrhs:输入参数数目
0 i" g2 d8 I0 z! B例如,使用/ \1 A  ~7 r" [  F4 S
[a,b]=test(c,d,e)
0 `6 Z7 \8 P& z/ ~* W" _, R/ W调用mex函数test时,传给test的这四个参数分别是
4 e' \8 U+ ~& l: W. T" }      2,plhs,3,prhs
  ~* }/ j0 O3 P( `( p+ e其中:
; |  G1 t9 ^+ G" Y: w/ a% oprhs[0]=c
# L% Z; A! x+ K  ]) G6 s& Jprhs[1]=d % d4 q, J! p" E
prhs[2]=e ' `) A7 e: `* A% _" r' i7 h$ p& }
当函数返回时,将会把你放在plhs[0],plhs[1]里的地址赋给a和b,达到返回数据的目的。  
# w1 c' A* R4 b细心的你也许已经注意到,prhs和plhs都是指向类型mxArray类型数据的指针。 这个类型是在mex.h中定义的,事实上,在Matlab里大多数数据都是以这种类型存在。当然还有其他的数据类型,可以参考Apiguide.pdf里的介绍。 ! R+ l. X9 |' v+ `8 X4 c

& ?+ i+ G7 ?8 V' s( F4 |; C 8 f+ J' e. t& P' f8 t5 n

) V, M4 [5 j: ]+ V//hello.c 2.0 " }" |  z* k! x
#include "mex.h"
; K- h" d* L1 bvoid mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
# S. L  y% P/ a# Y; k{# U; f+ M8 h) f$ v) j3 k2 Z. G( \
int i; . k: n. T4 p: @3 ^# q4 V7 M
i=mxGetScalar(prhs[0]); - k9 r& i. b( z% |9 J. h
if(i==1) : s6 y- S$ M  ^. W7 w3 s  O% g% m
  mexPrintf("hello,world!/n");
2 j' K" I, G2 \" ~# uelse
$ ?: M: F& z% w' G  mexPrintf("大家好!/n");
1 I* q( F- `- z}
* q& u5 c  D4 I8 f: y0 d4 U+ V; _! P3 Q; ^. t

. u, ^' p( D. A  f. e- U将这个程序编译通过后,执行hello(1),屏幕上会打出: hello,world!
; g5 s9 r7 R* a7 f4 }* y- j而hello(0)将会得到: 大家好!
+ @" x4 i: G4 N* A/ v; K3 b! F3 {: G4 m  q% o  ~5 W# v
用到了一个函数:mxGetScalar,调用方式如下:
# {7 N* I4 D' _0 D& ]; p, k  o/ k   i=mxGetScalar(prhs[0]); 1 l! j: p- |! O: U( D/ O
"Scalar"就是标量的意思。在Matlab里数据都是以数组的形式存在的,mxGetScalar的作用就是把通过prhs[0]传递进来的mxArray类型的指针指向的数据(标量)赋给C程序里的变量。这个变量本来应该是double类型的,通过强制类型转换赋给了整形变量i。
& c' C. \+ i$ E$ k9 x* }! E3 K5 L0 B4 V8 x

* Q/ Z/ Q' @1 \  B& S7 h% ?
9 {% Z4 k+ n3 H  ]//hello.c 2.1 ( \) F  U5 n& `2 U8 Q
#include "mex.h" 5 z3 b* Y& N5 m" n0 Y+ z
void mexFunction(int nlhs, mxArray *plhs[], / P% m3 k; t1 g3 ~- `+ q( Z+ p
int nrhs, const mxArray *prhs[])
/ n% L  L7 g) p, s% A; `. Y) q" i# U{ 2 D& E" I4 K0 F' C) @
int *i; 7 ^, F; m/ @, C# n, n
i=mxGetPr(prhs[0]);
8 f7 [* Z+ p% S$ j4 jif(i[0]==1)
& y! U- s! A5 }* m  mexPrintf("hello,world!/n"); 6 H6 L4 V5 ]2 _, z
else
6 g4 Z$ c: H  i4 A4 f  mexPrintf("大家好!/n");
8 _7 w3 Y) u" \6 E}
5 \- i, D0 M% D: p+ J  u) B5 I, b" M3 I6 l! n& R
+ U! ^* I; C: ~+ w0 u( ~  s
8 w! Q1 x6 O; i$ ?
这样,就通过mxGetPr函数从指向mxArray类型数据的prhs[0]获得了指向double类型的指针。
1 n4 e5 s& r0 e) _但是,还有个问题,如果输入的不是单个的数据,而是向量或矩阵,那该怎么处理呢 ?通过mxGetPr只能得到指向这个矩阵的指针,如果我们不知道这个矩阵的确切大小,就
7 f9 r" T, k' m" N( m没法对它进行计算。
) ]$ s  P; Z/ X为了解决这个问题,Matlab提供了两个函数mxGetM和mxGetN来获得传进来参数的行数 和列数。下面例程的功能很简单,就是获得输入的矩阵,把它在屏幕上显示出来: ( v% A+ K' b. c3 Z" i4 C

* t5 o: p1 n* y" W0 {5 o* @3 r6 Y! b% p: r) @
//show.c 1.0 & ?* U$ |0 Q' D7 ?% G* G1 r
#include "mex.h"
4 z( @8 [6 X& P7 _7 t* U  H( x#include "mex.h" 7 P7 p/ R2 z; \9 {" G
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) ' S! X) Y) C$ `
{ ( t6 E& g8 Z6 i5 x
double *data;
# @& c5 F: e0 [: Z0 c5 W9 y( c7 u( Rint M,N; / S* L2 r/ S$ u: n6 x: A
int i,j;
' C( P: K; j) g. L6 cdata=mxGetPr(prhs[0]); //获得指向矩阵的指针 - y+ I  x1 T+ u. u/ _+ I/ u: n
M=mxGetM(prhs[0]); //获得矩阵的行数 4 W: z6 d$ K; a5 w& Q6 t$ J7 t8 }) q
N=mxGetN(prhs[0]); //获得矩阵的列数 ( H- J  r9 j, ?
for(i=0;i<M;i++) & @! L, Z: K1 @; g, ^3 r& V
{   for(j=0;j<N;j++) , r3 D* ^) T4 w3 N' z
     mexPrintf("%4.3f  ",data[j*M+i]);
8 {& c$ H9 T2 t     mexPrintf("/n");   X0 H% y1 f  k" u
  }0 U4 l! C5 t- Q. y. O9 E6 u
}
* z1 d$ Y4 R$ y4 V2 U5 Z2 ?  ~, q9 w2 c
; q) d( _/ ]' k5 v4 N% B

$ E; G% V! W2 [8 C1 S+ |编译完成后,用下面的命令测试一下: ) p8 ^8 {# a' {! V) k
  a=1:10; 9 u% N: J& d* `8 w5 ]  k
  b=[a;a+1]; , o; p0 L% }+ @  f0 W( k
  show(a) + v0 v8 V( ?4 X( t# @& q! N
  show(b)
3 `6 t; w% Q2 R- y' k需要注意的是,在Matlab里,矩阵第一行是从1开始的,而在C语言中,第一行的序数为零,Matlab里的矩阵元素b(i,j)在传递到C中的一维数组大data后对应于data[j*M+i] 。
0 v( \6 \. ]0 J6 b% E) A输入数据是在函数调用之前已经在Matlab里申请了内存的,由于mex函数与Matlab共用同一个地址空间,因而在prhs[]里传递指针就可以达到参数传递的目的。但是,输出参数却需要在mex函数内申请到内存空间,才能将指针放在plhs[]中传递出去。由于返回指针类型必须是mxArray,所以Matlab专门提供了一个函数:mxCreateDoubleMatrix来实现内存的申请,函数原型如下:
. ^6 X0 J8 l1 r) p7 Q  x   mxArray *mxCreateDoubleMatrix(int m, int n, mxComplexity ComplexFlag)
2 M: g" N' ^! A7 e1 j0 \. O   m:待申请矩阵的行数 8 O4 V- \$ _# S4 d
   n:待申请矩阵的列数 7 H8 l7 Z0 O5 r/ u3 z% T4 Y0 i5 S
为矩阵申请内存后,得到的是mxArray类型的指针,就可以放在plhs[]里传递回去了。但是对这个新矩阵的处理,却要在函数内完成,这时就需要用到前面介绍的mxGetPr。使用 mxGetPr获得指向这个矩阵中数据区的指针(double类型)后,就可以对这个矩阵进行各种操作和运算了。下面的程序是在上面的show.c的基础上稍作改变得到的,功能是将输  
, w' }$ W( O/ R' b" N- w4 }; K% K0 e/ \
) N) h5 r; [6 q: m4 M5 J
6 o! c) d1 p: f" ]7 q
5 D( F: w# l! o+ z9 w
//reverse.c 1.0 9 ^, `; d( R5 q0 y( _
#include "mex.h" & O) W. t/ l" `. {. n, v* C
void mexFunction(int nlhs, mxArray *plhs[], 0 i8 W* A6 ?% t. `4 i. U
    int nrhs, const mxArray *prhs[]) * v) t* [! `& d5 i" F% Q
{ ) {6 u/ H( P5 h8 g* p& D" |
double *inData;
$ v) m. k" \' r) G6 Gdouble *outData; 6 |9 H0 M$ H  e0 T! X: l
int M,N;
; j! i$ ?- |6 {* O3 ~; Rint i,j;
( x' E" J1 X' N* G. Y3 h) C  oinData=mxGetPr(prhs[0]); . n5 D, j" G5 i3 t# W
M=mxGetM(prhs[0]);
2 h- F1 g8 R  n( B& p7 |9 y2 j! iN=mxGetN(prhs[0]); - D8 h# U! I; O" r
plhs[0]=mxCreateDoubleMatrix(M,N,mxREAL);
# ~- s2 e) H: u2 uoutData=mxGetPr(plhs[0]);   z$ W7 T4 K" j! m- G  }4 k8 @
for(i=0;i<M;i++) - `3 D) c8 u) q" h5 p5 Z4 D# r
  for(j=0;j<N;j++) ( ^1 R, a* m. N; A
   outData[j*M+i]=inData[(N-1-j)*M+i]; 9 K: v0 T! W8 W& ~; f" G
} , N1 J1 ^( R+ g" w3 i

' _6 O. a$ ^- b3 G9 U. y! H7 I! d! {9 X" `5 T6 D7 C

& W1 G1 c  V+ `; X. _当然,Matlab里使用到的并不是只有double类型这一种矩阵,还有字符串类型、稀疏矩阵、结构类型矩阵等等,并提供了相应的处理函数。本文用到编制mex程序中最经常遇到的一些函数,其余的详细情况清参考Apiref.pdf。 ) D& x; [8 n* I
通过前面两部分的介绍,大家对参数的输入和输出方法应该有了基本的了解。具备了这些知识,就能够满足一般的编程需要了。但这些程序还有些小的缺陷,以前面介绍的re由于前面的例程中没有对输入、输出参数的数目及类型进行检查,导致程序的容错性很差,以下程序则容错性较好/ i" x4 X- `3 c  q2 W+ h% Z% b
! s. H0 o9 b% X, Z( R
, q' n% X! ?# R5 `$ _, I- h# s
#include "mex.h"
( A% D! }% ~; x- A* r, u1 uvoid mexFunction(int nlhs, mxArray *plhs[],  int nrhs, const mxArray *prhs[]) : V+ b# l- q( M- ?! |% ]. j
{
" K7 R& E( }# c' bdouble *inData;   ?8 B: E3 U( d5 ^9 c" N5 s0 R+ q. h* p
double *outData;
! r; `" l/ e% ~; kint M,N;   ^0 x9 B& m+ [
//异常处理
7 D4 r3 Z' m8 N& M//异常处理
+ T1 |* q$ n6 w8 o. n# Gif(nrhs!=1) ( I! Z* _+ E0 Q2 I9 Y8 M
    mexErrMsgTxt("USAGE: b=reverse(a)/n"); ( {! v/ u' M( C+ M
  if(!mxIsDouble(prhs[0])) ( ^$ g4 u2 n9 @5 \1 Q. ?; Y. N
   mexErrMsgTxt("the Input Matrix must be double!/n"); % K6 s* A) ]9 B* W
   inData=mxGetPr(prhs[0]); $ }0 P, L2 X+ u8 Z
   M=mxGetM(prhs[0]);
8 P9 k. g$ H/ J$ C4 u   N=mxGetN(prhs[0]);
) M( Z8 s# N0 g! m  u   plhs[0]=mxCreateDoubleMatrix(M,N,mxREAL); % F. O$ M; Q; q6 Y
   outData=mxGetPr(plhs[0]);
; Z0 }% E' B; d; v: {! G   for(i=0;i<M;i++) 2 n1 C( _1 `8 I# M, W% e
     for(j=0;j<N;j++) , s* `5 l' ]* _! m7 v
     outData[j*M+i]=inData[(N-1-j)*M+i];
* f5 F) g4 m$ k: _: s  } " J8 @- e" T- M/ j
2 |* |% t2 a' n, n+ j
2 H  D8 m0 Q4 B& W
4 b, ^# t  F. p
在上面的异常处理中,使用了两个新的函数:mexErrMsgTxt和mxIsDouble。MexErrMsgTxt在给出出错提示的同时退出当前程序的运行。MxIsDouble则用于判断mxArray中的数据是否double类型。当然Matlab还提供了许多用于判断其他数据类型的函数,这里不加详述。 8 [; a0 Z# {" L: \
需要说明的是,Matlab提供的API中,函数前缀有mex-和mx-两种。带mx-前缀的大多是对mxArray数据进行操作的函数,如mxIsDouble,mxCreateDoubleMatrix等等。而带mx前缀的则大多是与Matlab环境进行交互的函数,如mexPrintf,mxErrMsgTxt等等。了解了这一点,对在Apiref.pdf中查找所需的函数很有帮助。. }% @* X) G3 ?  H" P
至此为止,使用C编写mex函数的基本过程已经介绍完了。 $ q3 t' T# w9 q+ Z9 G: M
. E. k/ ~* A; _

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-11-24 10:47 , Processed in 0.140625 second(s), 23 queries , Gzip On.

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

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

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