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

MATLAB调用C程序

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x

! [- k+ M. z. }) M) X' i1 v4 d' I  e通过把耗时长的函数用c语言实现,并编译成mex函数可以加快执行速度。6 M* F8 z3 F' ?2 {8 ^+ O# |+ C
5 K3 B8 l- c; S% U' p
Matlab本身是不带c语言的编译器的,所以要求你的机器上已经安装有VC,BC或Watcom C中的一种。
% h$ G0 ?8 A8 h0 k; |7 K0 O6 t1 M4 B, n4 S4 {1 O2 ~& K! a
如果你在安装Matlab时已经设置过编译器,那么现在你应该就可以使用mex命令来编译c语言的程序了。
& Q' z/ G2 h: @9 p4 u, C- ]
: K0 W- ^0 {, n如果当时没有选,就在Matlab里键入mex -setup,下面只要根据提示一步步设置就可以了。1 m+ B: v" `" y3 g: Z: n$ b

8 s7 H( v' t9 i7 W0 u  p. B
# J4 C: A" R7 z$ Q8 ]! j4 R" X& J: p; @( p: p7 l
为了测试你的路径设置正确与否,把下面的程序存为hello.c。' V8 ?# m2 [. b* a0 d, M

+ z& E' a/ H! v! `?
+ Y3 w2 h  ~0 _3 m/*hello.c*/
+ f% x  U& {8 [+ m0 X#include "mex.h"
4 s2 B1 q5 B+ Q# ]* x( Z# k) tvoid mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
1 ^, F3 X4 w2 y* K0 G5 c{ mexPrintf("hello,world!/n");- Z5 b7 O" o; K/ Y4 M9 w3 }
}. H. f% N- g6 u  w: J- S
假设你把hello.c放在了C:/TEST/下,在Matlab里用CD C:/TEST/ 将当前目录改为C:/ TEST/(注意,仅将C:/TEST/加入搜索路径是没有用的)。现在敲:" f$ r& F4 Q. z/ q3 o
mex hello.c 1 a' _' v0 I( ]9 \+ P1 ?! ]8 P
如果一切顺利,编译应该在出现编译器提示信息后正常退出。如果你已将C:/TEST/加入了搜索路径,现在键入hello,程序会在屏幕上打出一行:. _, B' l/ b! s$ H
hello,world!
4 z: `! M2 V9 ]
. f9 t3 t: @8 J! M5 s3 B9 ?整个程序由一个接口子过程 mexFunction构成。
) p5 U$ R: P7 Z, N7 V& N+ ^$ vvoid mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 7 D$ E. ?& L3 W! C; a) V, e- i: y
前面提到过,Matlab的mex函数有一定的接口规范,就是指这
2 Q9 e7 p* a' u& q/ o7 G1 b! w" xnlhs:输出参数数目
( i" J# a5 ~/ V1 dplhs:指向输出参数的指针 . I" A0 s, q( P" ^
nrhs:输入参数数目
  c* B: D# }  E( z例如,使用
# c# ]0 ]* D# T3 g" G" d0 N[a,b]=test(c,d,e)
, }( I' W% m$ r% ~5 f调用mex函数test时,传给test的这四个参数分别是3 w, s: S+ S, ?2 _& {
      2,plhs,3,prhs
' H6 i, [6 a7 x9 b7 P  \其中:
0 g; X; u/ N+ s$ v, @prhs[0]=c   ?/ m( h  O+ t4 w
prhs[1]=d , y; z6 X4 u# t! a
prhs[2]=e   b4 ], D) t& `' k. M
当函数返回时,将会把你放在plhs[0],plhs[1]里的地址赋给a和b,达到返回数据的目的。  
7 j) E/ R0 S/ _细心的你也许已经注意到,prhs和plhs都是指向类型mxArray类型数据的指针。 这个类型是在mex.h中定义的,事实上,在Matlab里大多数数据都是以这种类型存在。当然还有其他的数据类型,可以参考Apiguide.pdf里的介绍。
% Q& g7 v9 [/ e( e6 g4 |+ W) r2 T+ u, ?1 J; Z
9 _1 {7 O! N2 N4 S4 H1 [- m8 r

/ o) X' V( {# G7 K/ v7 U1 X' y//hello.c 2.0 ; ^  H5 l: N( T8 ]+ p5 U" ~: z
#include "mex.h" + l* ?" ^4 o& k7 [6 x
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) : S- T& K4 r+ f  A' o- s; m
{
% D2 y7 a0 q$ ^) Rint i;   U( y; P* k; R$ j2 N$ r  q, O3 v
i=mxGetScalar(prhs[0]);
! n3 p# k: b$ w, ]; Dif(i==1)
. s+ O% w9 L: |" m  mexPrintf("hello,world!/n");
" `' \" @8 t; \1 H2 lelse # d9 y% T7 L% q1 b0 }8 ^
  mexPrintf("大家好!/n");
! G' `$ }8 t' U4 \( ]8 q/ M}
% y: Q% ~. j5 J% W" c' Z
. F( D* r5 z1 B4 y4 i5 ?1 o
$ f) j( G3 H3 q- D% L* Z+ K+ y$ I+ H将这个程序编译通过后,执行hello(1),屏幕上会打出: hello,world! 8 [0 w7 h, t! I" M
而hello(0)将会得到: 大家好!
* o7 T8 ?8 j- P6 X2 j( Q
0 f7 Z/ ^; }: |: N  o+ f用到了一个函数:mxGetScalar,调用方式如下:
, S: u8 W: |1 C; b: ?   i=mxGetScalar(prhs[0]); 3 B! Q! A( H* {
"Scalar"就是标量的意思。在Matlab里数据都是以数组的形式存在的,mxGetScalar的作用就是把通过prhs[0]传递进来的mxArray类型的指针指向的数据(标量)赋给C程序里的变量。这个变量本来应该是double类型的,通过强制类型转换赋给了整形变量i。
! `, z* I4 l6 B" _* `+ }. m( J! ^
9 ~" G# p2 w# u/ K: q
$ a- `1 H) U2 \- K5 [: v- K
8 H' I: l3 z* Y//hello.c 2.1 : D% n! m% [$ L7 E% ~3 u
#include "mex.h"
. E- E6 u# L& a. ~1 g1 `; g% o3 [void mexFunction(int nlhs, mxArray *plhs[], + H! n5 V9 F( ^
int nrhs, const mxArray *prhs[]) 1 N5 g% w$ o8 N! r1 |  b
{
% H6 F% p! u; D4 ]  P7 ?' U* w/ ~int *i; # R- ]% i8 F1 c/ m2 l! e
i=mxGetPr(prhs[0]); 6 `9 g; {6 m( n6 L* q2 o: a$ h
if(i[0]==1) " Y; A. Z4 _. A& K) p$ C
  mexPrintf("hello,world!/n"); $ [' {- V! t2 v# h; C8 W7 F& A
else $ h5 n# I9 f5 W6 v# \* C- a# h
  mexPrintf("大家好!/n"); ( n$ l. F) I6 n! ]( ?
} # b8 c+ P8 @6 t( s2 ?  u! @
  z' B) e! O6 i% D  W

5 n. q6 Q; ~9 M* `2 b6 f8 Y8 i0 \+ I! T
这样,就通过mxGetPr函数从指向mxArray类型数据的prhs[0]获得了指向double类型的指针。7 k- J1 Q4 B6 l9 S; @5 @
但是,还有个问题,如果输入的不是单个的数据,而是向量或矩阵,那该怎么处理呢 ?通过mxGetPr只能得到指向这个矩阵的指针,如果我们不知道这个矩阵的确切大小,就 / G" J3 z4 Z+ R
没法对它进行计算。
* {: ^/ [2 s& f6 h+ m为了解决这个问题,Matlab提供了两个函数mxGetM和mxGetN来获得传进来参数的行数 和列数。下面例程的功能很简单,就是获得输入的矩阵,把它在屏幕上显示出来: 7 W4 x' I- g3 U8 X

4 D7 P" k' M/ Y9 V! E8 l! D6 Z" N% P# w+ Z) z) G
//show.c 1.0 ; C- e# `/ @1 {
#include "mex.h" . ?7 ?3 o+ T: X8 X: `$ d, g
#include "mex.h" 8 W1 t' W3 N" o
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
+ g) m, V3 Q+ n7 d{
% E( d5 y/ ]7 k: Y) @, Ddouble *data;
4 X% t( ]7 N' `3 W% }int M,N; ) y1 y% @; L* E; ^3 o# s8 V
int i,j; & g$ `6 f2 s- H
data=mxGetPr(prhs[0]); //获得指向矩阵的指针
: t! G+ a0 F) Y, D6 r  zM=mxGetM(prhs[0]); //获得矩阵的行数
0 i& O5 H% u- v0 M) I) C2 z$ sN=mxGetN(prhs[0]); //获得矩阵的列数
0 ~6 ?6 l+ |8 ]  E: [. N3 t+ j; Efor(i=0;i<M;i++) ' J: c" q) S5 H+ ]* w
{   for(j=0;j<N;j++)
8 K; S+ r' W! M7 K" ?  P* U* {# |! L     mexPrintf("%4.3f  ",data[j*M+i]);
% G' ~0 a3 ^# p5 q$ \9 {$ F, V     mexPrintf("/n");
6 y* l/ S7 d2 q9 w# Z  }
: |" O6 ?9 O% m3 L( ~} , F# B6 V+ d( o% B. B. O1 K

  ], i" P. n6 e/ p- o* l7 w& L% h* h % C8 [5 r; c* W: b% e, \# g9 ?( q

* h* v" a- r+ Y& A# @编译完成后,用下面的命令测试一下:
" F5 R( U+ G7 C6 e% @1 o  a=1:10;
9 S+ x! y+ _# Q9 T  w* E: X! X  b=[a;a+1];
; ?. w/ g) i; c0 V- t2 r7 Z  show(a)
' V9 O& @! w2 l/ G& q. L* t+ J  show(b)
: W0 s* E* f/ n4 _/ r, e需要注意的是,在Matlab里,矩阵第一行是从1开始的,而在C语言中,第一行的序数为零,Matlab里的矩阵元素b(i,j)在传递到C中的一维数组大data后对应于data[j*M+i] 。
$ t2 I8 [6 _4 [$ u: x+ x7 b输入数据是在函数调用之前已经在Matlab里申请了内存的,由于mex函数与Matlab共用同一个地址空间,因而在prhs[]里传递指针就可以达到参数传递的目的。但是,输出参数却需要在mex函数内申请到内存空间,才能将指针放在plhs[]中传递出去。由于返回指针类型必须是mxArray,所以Matlab专门提供了一个函数:mxCreateDoubleMatrix来实现内存的申请,函数原型如下:
, I3 c6 N4 O: E! ]! ^# _   mxArray *mxCreateDoubleMatrix(int m, int n, mxComplexity ComplexFlag) ) u4 N# @& F& {6 L, s  _
   m:待申请矩阵的行数 ! n6 O+ w0 u" j2 L+ f' V% I& t4 y, t
   n:待申请矩阵的列数
2 v, E8 F* y) ]) Q, c为矩阵申请内存后,得到的是mxArray类型的指针,就可以放在plhs[]里传递回去了。但是对这个新矩阵的处理,却要在函数内完成,这时就需要用到前面介绍的mxGetPr。使用 mxGetPr获得指向这个矩阵中数据区的指针(double类型)后,就可以对这个矩阵进行各种操作和运算了。下面的程序是在上面的show.c的基础上稍作改变得到的,功能是将输  3 R6 N8 Y" y+ X( H

4 G8 r( q% F; N/ ?, U, | . R5 Y7 Z! y; a$ P' I

) o5 j& A) m4 M9 k% d5 j" O5 V6 [: I
//reverse.c 1.0 $ C  Y( @) p" V% M# \+ p
#include "mex.h" 0 R) m. K4 r# t* _
void mexFunction(int nlhs, mxArray *plhs[], + q2 x* f5 ^7 ~) \; s  N( w) |
    int nrhs, const mxArray *prhs[])
. l" V9 J: ^5 K{   k# u6 x. o4 {  M
double *inData; * N; t1 r3 e# b. @7 \  n4 e
double *outData; 0 U" K! }) a$ I6 f( U! Z0 m" |: N
int M,N;
! e3 g. N7 r. d$ Pint i,j;
/ ]# s4 Z: y/ H6 l& \8 uinData=mxGetPr(prhs[0]); 4 p* F5 P0 x" P, ?# s
M=mxGetM(prhs[0]); # m: L* G' u# t3 p8 W4 h7 I
N=mxGetN(prhs[0]); 8 y9 o  S  X, Q# s5 O# `2 L
plhs[0]=mxCreateDoubleMatrix(M,N,mxREAL);
  P5 h% x2 X$ R3 YoutData=mxGetPr(plhs[0]);
. J# \, X8 ?- J6 Y% e" d& |# xfor(i=0;i<M;i++) 4 |: E1 {5 ^4 s
  for(j=0;j<N;j++) & w, b4 h+ ?& g
   outData[j*M+i]=inData[(N-1-j)*M+i]; ' \: R- T9 U( v2 i
} 1 T& a; y8 B+ b) f+ n' ]

- h7 ]1 c) [0 L* y: R& V( l7 F2 j  Y: t2 U; d
, D! T: }8 h! L6 \. e+ O/ y, u
当然,Matlab里使用到的并不是只有double类型这一种矩阵,还有字符串类型、稀疏矩阵、结构类型矩阵等等,并提供了相应的处理函数。本文用到编制mex程序中最经常遇到的一些函数,其余的详细情况清参考Apiref.pdf。
6 K3 t# p( y7 o# c1 e3 j通过前面两部分的介绍,大家对参数的输入和输出方法应该有了基本的了解。具备了这些知识,就能够满足一般的编程需要了。但这些程序还有些小的缺陷,以前面介绍的re由于前面的例程中没有对输入、输出参数的数目及类型进行检查,导致程序的容错性很差,以下程序则容错性较好& O% R: Y0 M1 |6 u

5 F4 V# ^2 V+ I. y
$ d# }3 l+ x) Y4 v) T( N) }* Z( f#include "mex.h"
- Q5 u+ u8 L. ?' w# K7 Y% Dvoid mexFunction(int nlhs, mxArray *plhs[],  int nrhs, const mxArray *prhs[]) * z# n. _; ?$ F
{
7 N6 T( E" O- I# U- Qdouble *inData; 3 r! @0 [) I( e9 v3 m( a5 g
double *outData;   z, S/ p) G/ K, e
int M,N;
  ~! k/ n8 @2 n4 D//异常处理
, z' d/ \: ?. @4 o2 t9 a! a//异常处理
' `% K! p1 Y6 ?' uif(nrhs!=1)
% b2 Q8 b4 m" X+ _5 @9 g  I4 ]    mexErrMsgTxt("USAGE: b=reverse(a)/n");
3 |# E9 t; n' T  G, K  if(!mxIsDouble(prhs[0])) - R. b7 P; V- E3 }8 Q: ^# ?
   mexErrMsgTxt("the Input Matrix must be double!/n"); ' `# f$ `+ N7 A- R& x6 _' p2 {* x
   inData=mxGetPr(prhs[0]); - Y5 h$ e! b2 c' ]4 Z
   M=mxGetM(prhs[0]); % ?6 m5 S; @4 D  @
   N=mxGetN(prhs[0]); % ^; [" Y8 M3 P& p! r6 A+ o) g% A
   plhs[0]=mxCreateDoubleMatrix(M,N,mxREAL);
7 E7 ]+ r2 x- `  v) W  I6 e8 u/ _   outData=mxGetPr(plhs[0]); 8 p$ I4 s3 K, s1 r
   for(i=0;i<M;i++)
2 k, i9 @( S: t     for(j=0;j<N;j++)
7 ]8 J3 w# E9 f6 z     outData[j*M+i]=inData[(N-1-j)*M+i];
$ f, a; P+ ]' H: H3 ]  } 6 f; Q) D+ |) J5 `! o; f. H1 K
9 b! Y8 }& _4 s( Q  }
. n, J0 Q3 L7 e/ ^

" l, S$ t6 k6 y& K, j在上面的异常处理中,使用了两个新的函数:mexErrMsgTxt和mxIsDouble。MexErrMsgTxt在给出出错提示的同时退出当前程序的运行。MxIsDouble则用于判断mxArray中的数据是否double类型。当然Matlab还提供了许多用于判断其他数据类型的函数,这里不加详述。
/ B% D2 W* F0 X  }: N2 h需要说明的是,Matlab提供的API中,函数前缀有mex-和mx-两种。带mx-前缀的大多是对mxArray数据进行操作的函数,如mxIsDouble,mxCreateDoubleMatrix等等。而带mx前缀的则大多是与Matlab环境进行交互的函数,如mexPrintf,mxErrMsgTxt等等。了解了这一点,对在Apiref.pdf中查找所需的函数很有帮助。) Z% t* {0 y2 K; t
至此为止,使用C编写mex函数的基本过程已经介绍完了。
% l' p% E% }- L3 v; w1 _
, |# ?6 \, P( s4 g- W+ Y% U$ ?

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-11-5 08:13 , Processed in 0.140625 second(s), 23 queries , Gzip On.

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

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

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