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

MATLAB调用C程序

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x

7 I6 f# `0 g! J通过把耗时长的函数用c语言实现,并编译成mex函数可以加快执行速度。/ c4 _& _2 o) n# u+ ]0 @) D

6 O2 T/ s0 \% U3 S1 eMatlab本身是不带c语言的编译器的,所以要求你的机器上已经安装有VC,BC或Watcom C中的一种。
7 n6 ~5 o9 }2 ^5 T: ^3 n& r5 }) V9 G$ ?! k, \3 K
如果你在安装Matlab时已经设置过编译器,那么现在你应该就可以使用mex命令来编译c语言的程序了。
" O) t% x: c/ L. Q- f, K0 w2 d9 P* \* M- T' d2 E
如果当时没有选,就在Matlab里键入mex -setup,下面只要根据提示一步步设置就可以了。
6 l/ w, {$ v# Z: p9 D+ M  ~) _( y9 Z" }* Y) W2 B" ~
0 B2 U" _" [' @% a4 {9 P
& z; e, w; i/ `0 {- z. r/ p
为了测试你的路径设置正确与否,把下面的程序存为hello.c。6 s% q3 g8 z6 h& {$ K
. x( ]$ v9 Z# A) N: f1 E
?, n7 c% J- r% f" f" _4 h
/*hello.c*/$ h# L8 x) v. _4 i9 i
#include "mex.h"! N0 b3 K& M5 C: t# u5 B
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])' I9 [* z. R  M0 a! j6 t  V5 M
{ mexPrintf("hello,world!/n");, J' l/ `, D5 c+ M
}7 g4 p: }9 @* M! v% ^4 c( j8 t; H9 \
假设你把hello.c放在了C:/TEST/下,在Matlab里用CD C:/TEST/ 将当前目录改为C:/ TEST/(注意,仅将C:/TEST/加入搜索路径是没有用的)。现在敲:
  V& f/ w7 L; b8 @" ~1 tmex hello.c + F. Z6 R7 s1 J6 r1 ^
如果一切顺利,编译应该在出现编译器提示信息后正常退出。如果你已将C:/TEST/加入了搜索路径,现在键入hello,程序会在屏幕上打出一行:
5 g% O# i+ i- Y& w+ mhello,world! 6 a. k% L6 o( z/ m8 @! D( W

, o; P4 V9 U8 _( x- G+ b- J整个程序由一个接口子过程 mexFunction构成。& Q0 w' t/ t7 _' _
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
; `+ w1 L0 o/ d0 @/ k前面提到过,Matlab的mex函数有一定的接口规范,就是指这
3 _: {+ m9 l/ N4 ^nlhs:输出参数数目 $ u& `2 D  n: `+ v' f6 G! X
plhs:指向输出参数的指针 6 ~3 f( R, e1 n; Q
nrhs:输入参数数目 , L+ U; i) p9 Q+ w0 K7 O, d( ~
例如,使用
& d1 ?; Z. K- C% r( W% Y( A, ^9 u[a,b]=test(c,d,e)  \4 f! |6 _. W! Q) I
调用mex函数test时,传给test的这四个参数分别是0 l6 A, O, A& ]7 n2 X
      2,plhs,3,prhs$ q+ t: i7 P9 ]& M- l/ C; H, L
其中:
. t' D* j3 S1 G" z" Z5 ~: vprhs[0]=c
& C/ z( B! F2 _4 Uprhs[1]=d
' }4 M2 \/ D, U. N! Y  Kprhs[2]=e ( D2 s" x# B; E6 u
当函数返回时,将会把你放在plhs[0],plhs[1]里的地址赋给a和b,达到返回数据的目的。  * {: L' `# b1 e
细心的你也许已经注意到,prhs和plhs都是指向类型mxArray类型数据的指针。 这个类型是在mex.h中定义的,事实上,在Matlab里大多数数据都是以这种类型存在。当然还有其他的数据类型,可以参考Apiguide.pdf里的介绍。
% t' W0 D0 c) A+ j. D
& U; O4 \, q; k4 M0 K* k- I( M, x
3 D0 D8 ^7 c4 l2 W2 }  E" j4 O- \6 l5 s0 t0 Y+ w5 ]
//hello.c 2.0 " v% ^- z# `$ c9 W. W! n3 d
#include "mex.h"
! O# o$ o# ~$ v% P$ q' d) zvoid mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
$ h& B# t' H* T( x+ ?{
: N5 E* n/ E' z. A4 H8 `- W. \int i; ) R7 H' r- X7 Q0 n5 ?
i=mxGetScalar(prhs[0]); - u1 R; ?+ I% U8 y+ `) r
if(i==1)   L' p+ {! F8 Y0 u0 R2 U0 _
  mexPrintf("hello,world!/n"); 4 |3 }3 z/ v( z
else 9 R* {7 e; Y5 l' o- s
  mexPrintf("大家好!/n");   @/ F' v3 w! ^" H4 A: W* u) r( A7 J5 K
}
* [% l# c! F% X1 D' F* \- s8 L& A
5 ^- X7 `- u! O) A
将这个程序编译通过后,执行hello(1),屏幕上会打出: hello,world!
* J8 T# c' {% ]- O, H+ T而hello(0)将会得到: 大家好!
- W4 _& d5 K- B6 R9 X5 `) T8 d" s7 Z( o: h- u
用到了一个函数:mxGetScalar,调用方式如下: 2 `4 r3 ^. _( r
   i=mxGetScalar(prhs[0]);
6 X; ?) g5 P# S1 {0 `"Scalar"就是标量的意思。在Matlab里数据都是以数组的形式存在的,mxGetScalar的作用就是把通过prhs[0]传递进来的mxArray类型的指针指向的数据(标量)赋给C程序里的变量。这个变量本来应该是double类型的,通过强制类型转换赋给了整形变量i。
* a  o/ y& p: L, L
7 `, r) Y. P9 [
, G3 a8 R; d3 @0 h: R
& ~  y6 k( Z$ E8 N3 S) b; ?) f: H//hello.c 2.1 ! f- _* U: B$ `+ X
#include "mex.h" - G% M, z  A$ n" d
void mexFunction(int nlhs, mxArray *plhs[], 5 ?5 b9 _" S0 l$ E  F! V' [4 k
int nrhs, const mxArray *prhs[])
' k# f% L% K3 ~4 ?{
6 x( u. |- W  Z5 Q+ _' ~0 B& nint *i;
9 R2 x; e8 R1 L& ?  K& s; ki=mxGetPr(prhs[0]);
, e' ?3 M; C( t7 T# ^& nif(i[0]==1)
. i+ N. k$ I$ y0 X3 h  mexPrintf("hello,world!/n");
; ?% b9 U% [. E8 }0 velse 6 [2 B& }, n$ I) u2 Q2 D) L4 `2 g
  mexPrintf("大家好!/n"); ( d* n. {3 U, B4 j7 Q; r) r* D% t
}
1 o8 I- e; p/ T7 h* v
: F% p' Z2 i6 @9 r- p8 D# N
1 G2 f- J( _& O  D
& {& r3 O. e+ F; |& ^这样,就通过mxGetPr函数从指向mxArray类型数据的prhs[0]获得了指向double类型的指针。: p1 R) q( \9 Z* b! V% z
但是,还有个问题,如果输入的不是单个的数据,而是向量或矩阵,那该怎么处理呢 ?通过mxGetPr只能得到指向这个矩阵的指针,如果我们不知道这个矩阵的确切大小,就 8 Q$ Q9 b7 Q0 ]6 a0 S0 q
没法对它进行计算。
# ^- M& i6 h# E为了解决这个问题,Matlab提供了两个函数mxGetM和mxGetN来获得传进来参数的行数 和列数。下面例程的功能很简单,就是获得输入的矩阵,把它在屏幕上显示出来: , V9 E4 a* s8 i9 d, L7 z, `( c& @6 ^" J$ T
# D& g, k0 m. R' c/ x0 Y
  d! O5 `& \; v% L& O, F% E1 j
//show.c 1.0
, D7 r8 S8 W" V" ]! v2 r#include "mex.h" 1 G7 I" ]$ Z; z& E0 M; e8 Q$ Z
#include "mex.h" + \: U' E6 L, V) ^* o& C& J
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 4 ^' o( J% N% Z) |
{ : z3 Q; g7 q0 I: ]: N; f4 u
double *data;
  m9 {7 [* D1 Qint M,N;
( v. f. }+ U; K; C2 rint i,j;
/ b, V0 L# Z$ b$ L. ~data=mxGetPr(prhs[0]); //获得指向矩阵的指针
0 w3 j1 X3 B1 ?* D! W4 ~6 D$ r1 ^M=mxGetM(prhs[0]); //获得矩阵的行数
5 f0 I; f. r% d1 Q# f* r% @9 Z* D- j/ N9 ~N=mxGetN(prhs[0]); //获得矩阵的列数
; t9 L+ O. p2 K( Y( Bfor(i=0;i<M;i++)
6 {/ ]7 p2 G) Y9 w7 p{   for(j=0;j<N;j++)
' p% U, P& S. C     mexPrintf("%4.3f  ",data[j*M+i]); / i9 G5 o0 M4 p" |
     mexPrintf("/n"); / W$ O7 A2 _6 Q+ j) v  _: d* F/ D. [4 g
  }. }9 [' r: m( f2 m
}
6 }5 I; k+ R: u' |* y. k- P! g/ Z9 Z4 t9 ?! L

# q! l9 I6 S  j2 O7 T# n6 h& Q$ B
' N/ e7 z: B$ O" J" O: z( C* n编译完成后,用下面的命令测试一下:
3 U+ U" G; n( w; ~- B: j, _: {2 O  a=1:10;
8 O8 B& M: R9 j# K5 k. b  b=[a;a+1];
8 M7 w, w8 N1 m. r. e8 t  show(a) ; C/ U+ e0 i0 G' j6 J! G
  show(b)
, \  H  a; _  B5 Q需要注意的是,在Matlab里,矩阵第一行是从1开始的,而在C语言中,第一行的序数为零,Matlab里的矩阵元素b(i,j)在传递到C中的一维数组大data后对应于data[j*M+i] 。
* m- B. l6 k2 k0 E输入数据是在函数调用之前已经在Matlab里申请了内存的,由于mex函数与Matlab共用同一个地址空间,因而在prhs[]里传递指针就可以达到参数传递的目的。但是,输出参数却需要在mex函数内申请到内存空间,才能将指针放在plhs[]中传递出去。由于返回指针类型必须是mxArray,所以Matlab专门提供了一个函数:mxCreateDoubleMatrix来实现内存的申请,函数原型如下:
! f" A. U  V/ S9 P# v+ t" e   mxArray *mxCreateDoubleMatrix(int m, int n, mxComplexity ComplexFlag)
) q' u  k! z  d5 Q   m:待申请矩阵的行数
6 a, Q: g# g2 r# l   n:待申请矩阵的列数
/ i( ^9 G( h. S( f为矩阵申请内存后,得到的是mxArray类型的指针,就可以放在plhs[]里传递回去了。但是对这个新矩阵的处理,却要在函数内完成,这时就需要用到前面介绍的mxGetPr。使用 mxGetPr获得指向这个矩阵中数据区的指针(double类型)后,就可以对这个矩阵进行各种操作和运算了。下面的程序是在上面的show.c的基础上稍作改变得到的,功能是将输  
% E+ [  j0 K% ?$ f3 w8 F, V: e, q2 w7 \5 f+ Q  c6 q4 X
3 F! n/ b  n% U; H# N* e3 W! Y
  b% z5 m- d- A* ^: A; m8 b; R
8 M& ^* C/ \( h& z
//reverse.c 1.0
% i" T* o" }) t" Y# q, B# N#include "mex.h"
, C- h% x) s. F* i/ J. G% f) `void mexFunction(int nlhs, mxArray *plhs[],
5 y; R( r+ E8 h" U$ W    int nrhs, const mxArray *prhs[])
, e' r# A& S/ G$ O5 N8 j{ & S- K* _* s: g9 \( L! ~/ p) |
double *inData; # k; Q& L- n/ }2 H  Y9 m
double *outData; 5 y' n% x7 ?2 V5 j& m) ]) m: O
int M,N;
: P( @4 n  O+ o! p9 G( D( jint i,j;
  `) m' l; j! u8 ]/ X) einData=mxGetPr(prhs[0]);   s5 B5 L+ e2 z& W0 F6 w  C/ e
M=mxGetM(prhs[0]); ( d2 C3 w0 U( b/ Z" ^8 J
N=mxGetN(prhs[0]); 1 H. B' e' P6 M8 B( k
plhs[0]=mxCreateDoubleMatrix(M,N,mxREAL); 2 Q8 s$ K# X& W* [
outData=mxGetPr(plhs[0]); - y# I5 e: k7 c
for(i=0;i<M;i++)
/ t7 G' ~7 N, X/ i  for(j=0;j<N;j++) $ R# d- p1 Z" c# R6 z
   outData[j*M+i]=inData[(N-1-j)*M+i];
  W8 @1 D" T  ?7 c9 _} 8 N% S& Y4 F8 N; R

* e) P3 r2 y% V  D
) e% N! e4 o, C, f/ }. h; g, e# p# I, i" ^. i* j* V
当然,Matlab里使用到的并不是只有double类型这一种矩阵,还有字符串类型、稀疏矩阵、结构类型矩阵等等,并提供了相应的处理函数。本文用到编制mex程序中最经常遇到的一些函数,其余的详细情况清参考Apiref.pdf。
: L  J3 J8 X& f) J  B通过前面两部分的介绍,大家对参数的输入和输出方法应该有了基本的了解。具备了这些知识,就能够满足一般的编程需要了。但这些程序还有些小的缺陷,以前面介绍的re由于前面的例程中没有对输入、输出参数的数目及类型进行检查,导致程序的容错性很差,以下程序则容错性较好) t4 s/ c9 {* q0 o* X

* K. M% P$ T8 |0 K4 c
& J+ k) n  f$ g4 @6 l4 P: v#include "mex.h" 7 k+ {5 c+ h7 }/ N9 I4 C. S
void mexFunction(int nlhs, mxArray *plhs[],  int nrhs, const mxArray *prhs[])
9 S9 b  ]% k0 U$ q; R6 j' s4 _{ ' g3 M; x) E1 X' x: M
double *inData; ; n0 X  h8 A% H3 x
double *outData;
( \0 a: s/ L/ ~6 f! j  `& Z; ~3 pint M,N;
  v2 q2 r. _% r+ o; c. ~5 a7 x//异常处理
4 S% j7 k  Q( |. E+ U//异常处理
7 S, N. A4 |: R9 Cif(nrhs!=1)
) S" H" U+ }  z3 n% N, p    mexErrMsgTxt("USAGE: b=reverse(a)/n"); # V" k0 t1 k$ i! V# V! v, v( q
  if(!mxIsDouble(prhs[0]))
+ C/ F6 |2 g/ @: a7 \   mexErrMsgTxt("the Input Matrix must be double!/n");
6 \7 N( S1 p! m9 j0 Z   inData=mxGetPr(prhs[0]); * w* O0 o9 j) X
   M=mxGetM(prhs[0]);
3 r. A2 f! ]/ {0 H7 P- k: o, K   N=mxGetN(prhs[0]);
& {1 r9 ~1 @; E/ k   plhs[0]=mxCreateDoubleMatrix(M,N,mxREAL);
. ^/ x; c5 s9 n5 K  h   outData=mxGetPr(plhs[0]); 6 O" ^' a, |# S, w* i9 b. j
   for(i=0;i<M;i++)
6 a2 S4 Q; Z2 K7 Q+ E     for(j=0;j<N;j++)
" z6 D3 k8 q5 ]( j* J. D7 t5 }     outData[j*M+i]=inData[(N-1-j)*M+i]; / g# m  k1 ?* B  Z$ {
  } 2 ?7 M( B; q# v7 x& N0 C/ u

! L; k, L* B, }& T, y3 A5 W
7 K4 u  ?+ V- a( B4 J2 \* B) l; l2 v
在上面的异常处理中,使用了两个新的函数:mexErrMsgTxt和mxIsDouble。MexErrMsgTxt在给出出错提示的同时退出当前程序的运行。MxIsDouble则用于判断mxArray中的数据是否double类型。当然Matlab还提供了许多用于判断其他数据类型的函数,这里不加详述。
; \! h- T  b5 a# x8 u需要说明的是,Matlab提供的API中,函数前缀有mex-和mx-两种。带mx-前缀的大多是对mxArray数据进行操作的函数,如mxIsDouble,mxCreateDoubleMatrix等等。而带mx前缀的则大多是与Matlab环境进行交互的函数,如mexPrintf,mxErrMsgTxt等等。了解了这一点,对在Apiref.pdf中查找所需的函数很有帮助。
' E# Y# D( L6 C. D" Y0 y& a' a; P; W至此为止,使用C编写mex函数的基本过程已经介绍完了。 ' _2 ~; Y2 `4 P' M) }
+ I6 M9 \7 q1 K* |: p; g+ I; G; A/ `

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-6-25 15:58 , Processed in 0.078125 second(s), 23 queries , Gzip On.

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

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

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