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

MATLAB调用C程序

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
) z7 I! P; w" ?
通过把耗时长的函数用c语言实现,并编译成mex函数可以加快执行速度。
0 {- D. O5 d2 }' R* T
  b' n; v3 ]1 ^$ X) YMatlab本身是不带c语言的编译器的,所以要求你的机器上已经安装有VC,BC或Watcom C中的一种。' d/ _8 g2 ~9 k
3 I1 v2 a9 l- g
如果你在安装Matlab时已经设置过编译器,那么现在你应该就可以使用mex命令来编译c语言的程序了。
( T7 V4 j3 p( a: k) {* v+ l
! z3 E  w# O' d5 N如果当时没有选,就在Matlab里键入mex -setup,下面只要根据提示一步步设置就可以了。* |/ P3 u. n) l: z) f6 Y! o

- W* r) \! R: z3 I0 v! N
' W0 ]# f( e) A& l
( \8 L3 o( X  K1 c3 T2 f' c为了测试你的路径设置正确与否,把下面的程序存为hello.c。
  S* H: N. o" S  u# u0 t: d  X# }/ F0 Q' H5 c& j  e
?, j, O' x5 _0 H% j( y! t1 @
/*hello.c*/
7 X/ b: \! t- ^; I! T7 @, Y#include "mex.h"4 }. j$ J4 `: N4 C& K" P
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])- }5 Y. I1 `' a9 d
{ mexPrintf("hello,world!/n");
. R* c, V" S2 h# n4 K* A}8 \; k7 G4 X- ]- u& D6 y& I1 P# N/ v
假设你把hello.c放在了C:/TEST/下,在Matlab里用CD C:/TEST/ 将当前目录改为C:/ TEST/(注意,仅将C:/TEST/加入搜索路径是没有用的)。现在敲:) T6 U) K4 C3 i5 ?4 R9 {9 ]" `1 D! [, r( Z
mex hello.c
; k+ Z  ~+ ~5 g: Q: r, c* t( M如果一切顺利,编译应该在出现编译器提示信息后正常退出。如果你已将C:/TEST/加入了搜索路径,现在键入hello,程序会在屏幕上打出一行:! m8 I4 {$ E; X: l: v+ i/ r
hello,world!
, w. B9 _+ W2 t, r* |3 q) ~) O7 x( \2 G. }6 f- ~/ n
整个程序由一个接口子过程 mexFunction构成。! e) |( K& d2 `+ a9 M# X6 M
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 2 g7 k! v5 p$ U! S0 J' o+ F* r+ a4 d
前面提到过,Matlab的mex函数有一定的接口规范,就是指这; e1 F" o. j& l( T8 A: Q+ U, P
nlhs:输出参数数目
5 Z$ B* m* k  G. D6 u  kplhs:指向输出参数的指针 7 n& J: J  `5 I1 {* y2 a
nrhs:输入参数数目
& t2 K2 {. ~" _7 j- b3 r例如,使用4 E+ s$ {) L0 ]" [* I0 @
[a,b]=test(c,d,e)/ m& w$ |' ]+ h) V( ^! P# k: t, C
调用mex函数test时,传给test的这四个参数分别是
: E( i: k$ f0 P& _9 ~' E0 J  n, M: V      2,plhs,3,prhs
: X. B2 n% q, |5 j. K其中:
/ {' H5 V! D) W9 E$ dprhs[0]=c ' a' C/ E  y1 `1 E. M' [2 }
prhs[1]=d 8 \" O0 Y5 B3 B4 \4 x
prhs[2]=e
, v/ Q0 d9 D8 y6 p3 Y5 G' B当函数返回时,将会把你放在plhs[0],plhs[1]里的地址赋给a和b,达到返回数据的目的。  ; N# r. A" o# H5 M  k
细心的你也许已经注意到,prhs和plhs都是指向类型mxArray类型数据的指针。 这个类型是在mex.h中定义的,事实上,在Matlab里大多数数据都是以这种类型存在。当然还有其他的数据类型,可以参考Apiguide.pdf里的介绍。 4 B2 o" H" B5 ]' c$ i) q

+ \' V& w8 g# U7 N
+ J2 f: Z% h0 C+ O! ~' u) Q+ a6 B% ]' I* m
//hello.c 2.0 4 t( e" l% N4 R
#include "mex.h" - p3 v( Y* f: ~8 o* g0 ^) l3 f
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) . j) m: |0 _; m2 R0 Z2 a& h
{
9 f6 G: b7 @$ c# vint i;
6 n& a- ~: \3 A* ?4 Ai=mxGetScalar(prhs[0]);
  e' @" y8 @9 rif(i==1) & k; \7 [, R/ i/ f9 e
  mexPrintf("hello,world!/n");
# _6 j) v* b$ z9 s1 ]( m0 Jelse & [& z4 H( ^% t
  mexPrintf("大家好!/n");
# J- z. L& x# q, m' v; ^/ h}
2 ?( v/ w3 {9 |" t7 W& [  O1 m! @
) ^1 I& O5 O9 C8 J% p9 I6 F3 q2 Z8 O, F. p3 @- S1 X
将这个程序编译通过后,执行hello(1),屏幕上会打出: hello,world!
, G2 W# w' G; w) w3 P  {; d而hello(0)将会得到: 大家好!' J" U( t. s: t( `( S6 C4 J
! D( Y" f' d! i7 ?$ A$ b
用到了一个函数:mxGetScalar,调用方式如下:
9 D/ U8 f8 O( d+ }$ y+ J2 j' u   i=mxGetScalar(prhs[0]);
. x$ ]& n( ]* R5 S"Scalar"就是标量的意思。在Matlab里数据都是以数组的形式存在的,mxGetScalar的作用就是把通过prhs[0]传递进来的mxArray类型的指针指向的数据(标量)赋给C程序里的变量。这个变量本来应该是double类型的,通过强制类型转换赋给了整形变量i。
2 D& u3 a5 [& G
+ e3 }% F& g7 i; E
0 o9 ^: m: J7 f. x! l, O! \
; z* q5 S9 t: \8 E//hello.c 2.1
/ T7 C+ _" W( n, p, N1 K0 N2 a8 G#include "mex.h"
# ^9 V$ q& `) F8 {8 B9 c: Zvoid mexFunction(int nlhs, mxArray *plhs[],
8 ?0 D, F- L+ T* R2 Iint nrhs, const mxArray *prhs[])
9 r2 S2 d% S) ]7 N7 b" q1 q{
" N- i" i. {/ r+ q! P1 O2 wint *i; # V; z# W9 }! X( L& f! C
i=mxGetPr(prhs[0]);
. S6 U" T# n$ zif(i[0]==1) ' ^2 ]6 T$ `7 f. _8 e2 i
  mexPrintf("hello,world!/n"); 6 _& C$ q# l& k1 Q
else 5 \: Z7 s+ L$ B; ~$ H6 h: {
  mexPrintf("大家好!/n"); + s0 Q: J5 J" D
}
. ]0 @+ L& n2 n, d: A. W" y- u4 H1 A. r' ]& @  {- S' z% u6 `3 u

& j7 t2 t( W7 O, c6 v$ J. N
- ]- U+ E9 g) d7 L这样,就通过mxGetPr函数从指向mxArray类型数据的prhs[0]获得了指向double类型的指针。
3 _! l* t) E) c: l& I但是,还有个问题,如果输入的不是单个的数据,而是向量或矩阵,那该怎么处理呢 ?通过mxGetPr只能得到指向这个矩阵的指针,如果我们不知道这个矩阵的确切大小,就
! Q) v) C7 t. j# i/ k& z8 P9 f没法对它进行计算。
" m1 @' D! W. v+ N3 @& X( e为了解决这个问题,Matlab提供了两个函数mxGetM和mxGetN来获得传进来参数的行数 和列数。下面例程的功能很简单,就是获得输入的矩阵,把它在屏幕上显示出来:
+ e- W9 r7 K$ X, J+ R/ b8 L! y! e) \7 H% e9 p) a7 T: O

; o! C0 W. i( m7 x6 Y0 U1 J& l3 p//show.c 1.0 * |" j/ Z! H: p; T4 R/ @% ~
#include "mex.h"
  h8 W( ^+ s# V, S9 s1 G#include "mex.h" - H2 Q$ |/ ~" p) Y! O9 K" {/ A
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 5 U: ~7 s2 m1 Y+ s4 {; O
{
2 u0 C, e7 D' Jdouble *data; % ]$ R) f! n/ g3 N1 e
int M,N;
7 o  e! Q+ g+ h3 i4 y# Wint i,j; ) K  Z- y' f. h4 [
data=mxGetPr(prhs[0]); //获得指向矩阵的指针 0 @. k9 {. [3 F; i' X. V& b
M=mxGetM(prhs[0]); //获得矩阵的行数 / x# _1 y. h7 g
N=mxGetN(prhs[0]); //获得矩阵的列数 9 N4 _4 Y+ ^6 B+ M% W/ j& z
for(i=0;i<M;i++) $ n8 }# B5 d- b' t( v) D' `. S1 ?
{   for(j=0;j<N;j++)
3 e6 ?  x  y8 u2 `; E     mexPrintf("%4.3f  ",data[j*M+i]); 8 R! T3 J4 Q; O  \/ D. Y
     mexPrintf("/n"); ) q# |9 I- G1 ^
  }: r3 k9 X: q+ n. C0 V! o* U5 ~
}
4 x7 a! [' t- p1 S0 c# P( O% E7 p+ N% D! @: u! C

1 i4 U1 j4 _) e' x, s3 M" Z7 G9 D$ i: S; c/ |; _
编译完成后,用下面的命令测试一下:
# q) X, y% n- {, z' R5 n( u  a=1:10; ( Q/ @( G0 x# ?" |6 n
  b=[a;a+1]; 8 g* b: `' u/ D+ S3 M3 |% j+ ^
  show(a) 3 S* D- \: I4 S6 M! Q
  show(b) 7 e2 x- t! R; h, [/ l( Y" f1 G4 @
需要注意的是,在Matlab里,矩阵第一行是从1开始的,而在C语言中,第一行的序数为零,Matlab里的矩阵元素b(i,j)在传递到C中的一维数组大data后对应于data[j*M+i] 。
. O& R2 C) k- [输入数据是在函数调用之前已经在Matlab里申请了内存的,由于mex函数与Matlab共用同一个地址空间,因而在prhs[]里传递指针就可以达到参数传递的目的。但是,输出参数却需要在mex函数内申请到内存空间,才能将指针放在plhs[]中传递出去。由于返回指针类型必须是mxArray,所以Matlab专门提供了一个函数:mxCreateDoubleMatrix来实现内存的申请,函数原型如下:
9 x$ _. m2 I4 s3 ~3 q; S   mxArray *mxCreateDoubleMatrix(int m, int n, mxComplexity ComplexFlag)
0 ^3 O. E& \9 J1 A4 _   m:待申请矩阵的行数
! [1 K2 A: @5 |% d3 [  z; c. W   n:待申请矩阵的列数
- Q* l# X3 q+ c4 k: Y为矩阵申请内存后,得到的是mxArray类型的指针,就可以放在plhs[]里传递回去了。但是对这个新矩阵的处理,却要在函数内完成,这时就需要用到前面介绍的mxGetPr。使用 mxGetPr获得指向这个矩阵中数据区的指针(double类型)后,就可以对这个矩阵进行各种操作和运算了。下面的程序是在上面的show.c的基础上稍作改变得到的,功能是将输  
0 a; s) i7 M4 V# n6 r% P0 S# k; |9 b5 X! I! [7 W
, \% ~) W3 F9 j. B
- X1 l- P& t  Y1 y1 y5 p
1 R  b. q/ K1 n3 Z
//reverse.c 1.0
' ?: H- i, n1 J, m2 n/ R/ a#include "mex.h"
6 Q, s( E# o; G1 gvoid mexFunction(int nlhs, mxArray *plhs[],
. N  n4 V' `, g    int nrhs, const mxArray *prhs[])
$ [$ o" u0 t% w0 O2 h! l{ % S4 R. V) l6 X8 f6 m8 @- w  P. q; [
double *inData; ! h! A' V4 E* Q2 q
double *outData; : ?1 o2 ?4 `7 U0 F' H8 M
int M,N; 5 h9 V% e% _4 ^7 o% i7 c) \! C
int i,j; ) w0 k6 G) ~  S
inData=mxGetPr(prhs[0]);
: j! `) n) {6 C9 `M=mxGetM(prhs[0]);
6 J& w! C. j8 v0 mN=mxGetN(prhs[0]);
6 K" j/ C+ J: v* a8 tplhs[0]=mxCreateDoubleMatrix(M,N,mxREAL);
, [& i2 {4 j- L. |, ~8 G3 Z, @outData=mxGetPr(plhs[0]);
6 U, W/ u. q9 }& Lfor(i=0;i<M;i++)
5 N: L0 c0 X  l, S+ G  for(j=0;j<N;j++) ; L+ a+ H7 @0 J3 @0 Q* i7 ?
   outData[j*M+i]=inData[(N-1-j)*M+i]; & Z+ r, s9 q  ~  s' L! f6 D
} ' w( C0 y" g) M
- j- S/ S2 m% d; ~$ i+ w6 a

1 _0 ~! X9 Q# Q8 P" R! m5 g: L' f6 D: V# G. @3 G$ g
当然,Matlab里使用到的并不是只有double类型这一种矩阵,还有字符串类型、稀疏矩阵、结构类型矩阵等等,并提供了相应的处理函数。本文用到编制mex程序中最经常遇到的一些函数,其余的详细情况清参考Apiref.pdf。 8 _2 Q$ \3 K( q' e; f$ u- D
通过前面两部分的介绍,大家对参数的输入和输出方法应该有了基本的了解。具备了这些知识,就能够满足一般的编程需要了。但这些程序还有些小的缺陷,以前面介绍的re由于前面的例程中没有对输入、输出参数的数目及类型进行检查,导致程序的容错性很差,以下程序则容错性较好: W( b" p! _4 @$ R7 h, W- j/ ]. J
+ M7 p+ e+ J3 u9 T8 L' m, ]- C

' `' O- |1 Y" _/ {3 X( u#include "mex.h" * Z! ]! l9 ^5 u/ G0 m( k0 C
void mexFunction(int nlhs, mxArray *plhs[],  int nrhs, const mxArray *prhs[]) * @1 V6 g; A. n+ B' @
{ # Z7 F. b% b& P) H7 @. t
double *inData;
' U- |, ^! c( k5 K9 qdouble *outData; . E& T  Z9 q$ D% {! G
int M,N;
& h% R1 n1 {( |% T# v8 o; p//异常处理 ; m  G* G+ F  x* J' n  ]
//异常处理
. i) ?9 }$ g0 z0 qif(nrhs!=1)
; W+ a+ z2 m$ n, A    mexErrMsgTxt("USAGE: b=reverse(a)/n"); * c0 l+ z  E- q' K* }' V
  if(!mxIsDouble(prhs[0]))
, V. s0 B( W% C0 g& H) r. H' l  [% h6 p   mexErrMsgTxt("the Input Matrix must be double!/n"); + e0 C& @  Y- Y
   inData=mxGetPr(prhs[0]);
. A4 e3 D% O1 D  L7 Y   M=mxGetM(prhs[0]);
3 |. [5 j% G% W* \3 Z" P! s; e" Y1 K! \' W   N=mxGetN(prhs[0]);
. H. b) ^" H! ?' u2 `# @9 r0 T   plhs[0]=mxCreateDoubleMatrix(M,N,mxREAL); % h6 M! e/ S& n
   outData=mxGetPr(plhs[0]); $ e1 r9 w$ @/ R
   for(i=0;i<M;i++) - z; d" ]8 [: N* ]# v8 a, _
     for(j=0;j<N;j++) * u2 N7 Y2 n; ~8 n0 a3 A
     outData[j*M+i]=inData[(N-1-j)*M+i]; : V  X: E7 s% e
  }
1 C2 [' q0 ~- G3 `) ~+ Y2 B& I6 W/ _' P7 a/ [4 r' V
1 C+ E4 q+ p+ p( w9 c, i0 M2 B
7 X1 D! a  r1 {" c* O
在上面的异常处理中,使用了两个新的函数:mexErrMsgTxt和mxIsDouble。MexErrMsgTxt在给出出错提示的同时退出当前程序的运行。MxIsDouble则用于判断mxArray中的数据是否double类型。当然Matlab还提供了许多用于判断其他数据类型的函数,这里不加详述。
! U  h7 u; [. O1 J7 K需要说明的是,Matlab提供的API中,函数前缀有mex-和mx-两种。带mx-前缀的大多是对mxArray数据进行操作的函数,如mxIsDouble,mxCreateDoubleMatrix等等。而带mx前缀的则大多是与Matlab环境进行交互的函数,如mexPrintf,mxErrMsgTxt等等。了解了这一点,对在Apiref.pdf中查找所需的函数很有帮助。* {; z( S9 n# J2 ]0 c3 `
至此为止,使用C编写mex函数的基本过程已经介绍完了。
7 N7 l6 |/ f4 Q5 S
& s, H  ]0 z. G( ?  P, }' x1 d

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

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

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

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

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