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

MATLAB调用C程序

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x

2 C6 z7 C8 t5 _( l! @/ k0 e通过把耗时长的函数用c语言实现,并编译成mex函数可以加快执行速度。
8 e! W6 L7 c! j3 a' ^6 V0 A6 _: v6 A4 L; b" X
Matlab本身是不带c语言的编译器的,所以要求你的机器上已经安装有VC,BC或Watcom C中的一种。
7 X: y6 E. X) j1 l
0 l3 [; g/ d# d9 Y9 J如果你在安装Matlab时已经设置过编译器,那么现在你应该就可以使用mex命令来编译c语言的程序了。5 b* q+ @* |% w8 e

  w% F1 ?3 X6 @如果当时没有选,就在Matlab里键入mex -setup,下面只要根据提示一步步设置就可以了。
- h  C, a+ j. z+ I/ Z6 a$ @3 A0 ]" a' }& K. k

$ j0 \! h: l+ U7 A1 p
5 ^3 s/ s5 G$ Y/ h, s. x为了测试你的路径设置正确与否,把下面的程序存为hello.c。! v5 ]) q9 v0 j3 i5 W, A
  Z8 ?1 t* D. Q2 X0 V# K
?1 O. p; Y4 h4 R- a
/*hello.c*/0 P3 Y' b0 m, B2 \) A) B0 I8 m
#include "mex.h"
! o2 }5 E9 x0 D4 o0 R; F% qvoid mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
3 ~5 p5 D( S  P, P! x6 {{ mexPrintf("hello,world!/n");
1 N3 ]9 ?2 i$ H) B0 S4 `$ N}- I  B  C0 y0 M5 U8 h- M/ x: ?# Y
假设你把hello.c放在了C:/TEST/下,在Matlab里用CD C:/TEST/ 将当前目录改为C:/ TEST/(注意,仅将C:/TEST/加入搜索路径是没有用的)。现在敲:
# D: J0 W0 F$ T% e0 ~0 g5 c9 tmex hello.c 4 e7 Y; K5 M# ]9 t: U/ G
如果一切顺利,编译应该在出现编译器提示信息后正常退出。如果你已将C:/TEST/加入了搜索路径,现在键入hello,程序会在屏幕上打出一行:0 x6 }- P9 D" P) e' d) k0 t% z
hello,world! 5 H. m9 c2 w  n! a; l

) V4 ]4 j0 O; @: T0 j& @; P整个程序由一个接口子过程 mexFunction构成。3 z( `9 U  ?% c' k" c
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) / r4 j; r/ @' q. j2 v8 y; t
前面提到过,Matlab的mex函数有一定的接口规范,就是指这
2 \7 R5 n* i2 K% z' S: Gnlhs:输出参数数目
. C$ u  l+ x& `: Qplhs:指向输出参数的指针 + p3 _0 J+ d2 Q
nrhs:输入参数数目
4 w& u+ N/ n% r+ V例如,使用
+ v8 h% G1 m) L; n[a,b]=test(c,d,e)  y+ {' i+ d# b. m: Z$ N$ Z, t4 P+ ?
调用mex函数test时,传给test的这四个参数分别是
2 x' X+ E" Q! `/ L; \' ]/ X      2,plhs,3,prhs) F4 ]. U+ @2 k& f. x
其中: ' H  ]! S' T5 u. V! i  r/ r, K
prhs[0]=c * p4 n* E; N  J' u# E# ^- K
prhs[1]=d
' }, A, c& T2 V. L3 d# Oprhs[2]=e : h  y) J6 i7 z0 w+ n9 P$ y
当函数返回时,将会把你放在plhs[0],plhs[1]里的地址赋给a和b,达到返回数据的目的。    y$ O4 X+ B+ r* C5 }: V" s
细心的你也许已经注意到,prhs和plhs都是指向类型mxArray类型数据的指针。 这个类型是在mex.h中定义的,事实上,在Matlab里大多数数据都是以这种类型存在。当然还有其他的数据类型,可以参考Apiguide.pdf里的介绍。
8 G, E; |# Z4 y+ g  u: j. S+ d6 h2 L# o" e! B

9 b" l" V0 o3 \' ]* q  m) [; S  \) S" }1 B
//hello.c 2.0 % h- }+ r! }& F' }
#include "mex.h" - e1 l+ D7 F6 s
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
  I! r6 R1 _' N, ~) E; O* @9 ]{' z, I& O' o9 V' _
int i;
& e. @/ P/ f6 }/ vi=mxGetScalar(prhs[0]); ) r6 r' I# k5 y5 k$ g
if(i==1)
5 S2 E0 }3 u, ~! u( a  mexPrintf("hello,world!/n"); ! {; a, b$ l4 q, o
else
$ G0 Z3 H3 v7 j1 q  mexPrintf("大家好!/n");
" Y" R0 _7 N4 x8 H}$ i& Q5 r! f  X9 A$ Y+ h

4 ?2 a( p; s& B+ }+ A+ w/ D0 J2 I/ \0 u* M/ x6 r! z/ u
将这个程序编译通过后,执行hello(1),屏幕上会打出: hello,world! % z9 X9 f+ G* x1 V# n/ \
而hello(0)将会得到: 大家好!
3 H8 u# M% F3 F) T2 `4 g" d; `  O
1 o+ t( D2 m+ K. B用到了一个函数:mxGetScalar,调用方式如下:
7 f& C& K# ^/ g   i=mxGetScalar(prhs[0]);
' s8 ?# Q& f7 m& p1 X0 n% u7 k"Scalar"就是标量的意思。在Matlab里数据都是以数组的形式存在的,mxGetScalar的作用就是把通过prhs[0]传递进来的mxArray类型的指针指向的数据(标量)赋给C程序里的变量。这个变量本来应该是double类型的,通过强制类型转换赋给了整形变量i。1 k8 m2 P* [3 X, ^

+ ~7 g( `; Q* f; J, H
( @6 o6 y8 o) }( `( h* B  o$ f
& O7 _1 ^5 a+ t7 k2 m//hello.c 2.1
8 m& l' ~" E6 f7 z#include "mex.h"
7 A$ _8 F! z& i# I) E8 ]* P  lvoid mexFunction(int nlhs, mxArray *plhs[],
. s& \" U, c1 q5 mint nrhs, const mxArray *prhs[]) " A  [& D3 Z8 z2 `% ?
{ : `5 p& d" s6 x
int *i;
: n+ [+ x4 @, K" I$ R1 Li=mxGetPr(prhs[0]);
% [" s7 f! ^% [if(i[0]==1)
* `3 ]6 N! X: E* p/ \- [  mexPrintf("hello,world!/n");
2 l! D4 ~/ r$ Z4 m5 n. Nelse + S3 _" R  ]" e) X; G% T
  mexPrintf("大家好!/n"); ' W$ d6 j* w5 j
}
" K9 v% E8 k8 T: d* J6 t/ q3 F3 B6 I6 B! r  u8 q5 Z

8 G  R' p4 Y, e; }2 |/ N1 K/ L0 L5 H% E: T' ]) ~# X1 @' U! R
这样,就通过mxGetPr函数从指向mxArray类型数据的prhs[0]获得了指向double类型的指针。
5 f, F& y0 [5 O1 a但是,还有个问题,如果输入的不是单个的数据,而是向量或矩阵,那该怎么处理呢 ?通过mxGetPr只能得到指向这个矩阵的指针,如果我们不知道这个矩阵的确切大小,就 , C% a! p( U5 J3 ~+ g5 K$ R
没法对它进行计算。 . T: ^% ]$ d( U2 h# X
为了解决这个问题,Matlab提供了两个函数mxGetM和mxGetN来获得传进来参数的行数 和列数。下面例程的功能很简单,就是获得输入的矩阵,把它在屏幕上显示出来: $ Q( u4 B% @( E
1 U0 w  d( H5 a) f! y+ M( e0 k
. R) k4 C4 u, ^) ~
//show.c 1.0
1 ^9 b. m" Y( |#include "mex.h" ) I$ |; c! P4 K( G6 K$ C7 W: g
#include "mex.h" ' s% j8 W8 b% I- O8 P9 }& y
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) + }2 P. g  T8 E; e3 x& w/ d- X
{ 5 u5 e, |% k8 Q' a& _( n
double *data;
3 p1 }# O8 z# b; t: W/ [int M,N; 2 g+ y3 \# J. r
int i,j;
8 w9 G1 \3 t7 R( Y3 Sdata=mxGetPr(prhs[0]); //获得指向矩阵的指针
3 [7 s; a" G4 F" wM=mxGetM(prhs[0]); //获得矩阵的行数
/ ~& f7 Y9 m' j/ UN=mxGetN(prhs[0]); //获得矩阵的列数 9 m/ [7 C( |& ~1 G
for(i=0;i<M;i++)   V% g$ U6 P. I" F' C
{   for(j=0;j<N;j++) 8 j. z2 ^: E& Y2 o8 E8 y' Y, \
     mexPrintf("%4.3f  ",data[j*M+i]);
2 V6 l  @& s4 R6 W' W) b     mexPrintf("/n"); 3 e! _8 o2 m7 m. Q$ h
  }
0 r8 C9 \% |' q} 8 C( J7 N9 D2 U& b' R
6 w) a& q2 l# a" j( M
) X! R$ u, D. \

( m+ M( m) R4 q: a+ e4 z编译完成后,用下面的命令测试一下: $ K- X" q3 v  h/ a! V
  a=1:10; ) b7 I3 W# F; [9 h6 j: O
  b=[a;a+1]; & F8 @1 `% `! d
  show(a) 5 j0 Q8 ~& q1 I8 d& `" v: r" X8 L* n
  show(b) * t' }# |4 O" ~7 Q- A& B0 [& x
需要注意的是,在Matlab里,矩阵第一行是从1开始的,而在C语言中,第一行的序数为零,Matlab里的矩阵元素b(i,j)在传递到C中的一维数组大data后对应于data[j*M+i] 。 , B) x- e/ o8 v8 p! q4 @9 Q$ f
输入数据是在函数调用之前已经在Matlab里申请了内存的,由于mex函数与Matlab共用同一个地址空间,因而在prhs[]里传递指针就可以达到参数传递的目的。但是,输出参数却需要在mex函数内申请到内存空间,才能将指针放在plhs[]中传递出去。由于返回指针类型必须是mxArray,所以Matlab专门提供了一个函数:mxCreateDoubleMatrix来实现内存的申请,函数原型如下:
6 K/ E/ ^- x+ E7 b   mxArray *mxCreateDoubleMatrix(int m, int n, mxComplexity ComplexFlag)
5 R9 m, L2 }- |+ U% Y   m:待申请矩阵的行数
( a' h7 i( Q% R$ l9 S   n:待申请矩阵的列数 ; U# b' T! H6 s( M4 E
为矩阵申请内存后,得到的是mxArray类型的指针,就可以放在plhs[]里传递回去了。但是对这个新矩阵的处理,却要在函数内完成,这时就需要用到前面介绍的mxGetPr。使用 mxGetPr获得指向这个矩阵中数据区的指针(double类型)后,就可以对这个矩阵进行各种操作和运算了。下面的程序是在上面的show.c的基础上稍作改变得到的,功能是将输  
! A( C8 U6 B+ c9 g' T4 i7 Q9 B
& o- t! ^0 ^8 Q& f % c( Z" n+ @+ L9 v

$ X" K) o" `# j" x1 a6 ]/ k! G
0 t9 Z9 X% K1 \7 u# `  S' M: g//reverse.c 1.0
, T/ A1 l8 k  u#include "mex.h" / a# M! U& z. D0 j( {
void mexFunction(int nlhs, mxArray *plhs[],
3 Z. C* N7 f8 Q9 v' R    int nrhs, const mxArray *prhs[]) * |( y+ A8 p, ], s# z
{ . D8 j9 ?7 R( _4 e$ V
double *inData; ; D/ s+ o1 l3 O; k" E7 H0 S
double *outData;
6 _0 H3 f9 |% C* s. W* tint M,N;
( f9 o" _" K5 V. nint i,j; % \) D5 i& Y2 ]9 e  }: n; p! p) o
inData=mxGetPr(prhs[0]);
" _7 Z* x7 H! O/ J) AM=mxGetM(prhs[0]);
( \, S$ m3 |9 YN=mxGetN(prhs[0]);
3 Y6 s: c: M$ G5 Nplhs[0]=mxCreateDoubleMatrix(M,N,mxREAL); 3 b1 n( d5 Q" X) ^$ Y7 t( r
outData=mxGetPr(plhs[0]);
7 Y/ K" V+ d- X3 F2 @for(i=0;i<M;i++) 7 p) r* Y8 Q0 U/ ]
  for(j=0;j<N;j++)
) r  `5 x: W  {, T$ F4 D   outData[j*M+i]=inData[(N-1-j)*M+i]; ' d' Z" n' }9 c5 d, i+ D
}
! A8 \7 l) y+ |! M' O5 s- r( n6 x0 g: C7 n1 g
9 m- D8 S1 l4 _5 Z6 `. j

7 U2 U* D6 ]4 A! [5 M1 Z# ^" m当然,Matlab里使用到的并不是只有double类型这一种矩阵,还有字符串类型、稀疏矩阵、结构类型矩阵等等,并提供了相应的处理函数。本文用到编制mex程序中最经常遇到的一些函数,其余的详细情况清参考Apiref.pdf。 6 q5 |; e7 u$ T8 F( N
通过前面两部分的介绍,大家对参数的输入和输出方法应该有了基本的了解。具备了这些知识,就能够满足一般的编程需要了。但这些程序还有些小的缺陷,以前面介绍的re由于前面的例程中没有对输入、输出参数的数目及类型进行检查,导致程序的容错性很差,以下程序则容错性较好
; ~/ B" z$ ~& |5 Z' e& |( K/ }  F% u' ]8 @

. y. H2 W' }. C) }1 Z$ ^5 Q5 O#include "mex.h" 4 s' ?7 Y% w- a8 ~) J, G8 n
void mexFunction(int nlhs, mxArray *plhs[],  int nrhs, const mxArray *prhs[]) 9 p% E. d# l, Y0 ^  V
{ . x: w9 q* D9 s9 l7 N/ T$ e$ l
double *inData;
7 n  d( i% S. Z$ e1 U9 @; cdouble *outData; - @% x9 n0 |. r5 M! x% I! P7 ^
int M,N; 8 k. H4 a4 u1 u- T
//异常处理 2 b" f( n2 B3 ]" Y
//异常处理 # r% S! f' a( b7 G6 y2 n
if(nrhs!=1) ) `, }" k0 U3 r8 |' @1 B
    mexErrMsgTxt("USAGE: b=reverse(a)/n");
; Q: j/ N' j) \  if(!mxIsDouble(prhs[0]))
8 e' u9 R; ~6 Q4 D, l   mexErrMsgTxt("the Input Matrix must be double!/n"); $ z2 c2 n' o5 ~
   inData=mxGetPr(prhs[0]);
; L1 H. C& l* b   M=mxGetM(prhs[0]); 8 E! }* z' D8 R0 x  o  D+ V
   N=mxGetN(prhs[0]); ) E+ i6 d8 g& @/ T
   plhs[0]=mxCreateDoubleMatrix(M,N,mxREAL);
; F2 v. U- |( M5 U- t; {7 y   outData=mxGetPr(plhs[0]);
% e3 t* f: i) y$ `) d# E4 ]   for(i=0;i<M;i++) 6 t: @, Q5 _8 ?; Y; D3 h
     for(j=0;j<N;j++)
2 x# A8 n* `! ?$ H5 Q     outData[j*M+i]=inData[(N-1-j)*M+i];
) f! V2 L* }& _8 u  G& `  }
1 p( Y" b: Z# ^
, E5 H; o' A8 P0 u! R0 Y6 _3 | / N8 ~1 Q2 g& ?, J

2 c: i' Y  k6 v; j% H在上面的异常处理中,使用了两个新的函数:mexErrMsgTxt和mxIsDouble。MexErrMsgTxt在给出出错提示的同时退出当前程序的运行。MxIsDouble则用于判断mxArray中的数据是否double类型。当然Matlab还提供了许多用于判断其他数据类型的函数,这里不加详述。 & A8 t! e( H# o6 O" J. W
需要说明的是,Matlab提供的API中,函数前缀有mex-和mx-两种。带mx-前缀的大多是对mxArray数据进行操作的函数,如mxIsDouble,mxCreateDoubleMatrix等等。而带mx前缀的则大多是与Matlab环境进行交互的函数,如mexPrintf,mxErrMsgTxt等等。了解了这一点,对在Apiref.pdf中查找所需的函数很有帮助。7 ]" W; |0 ]# q: ^; e' J4 w% h( P
至此为止,使用C编写mex函数的基本过程已经介绍完了。
0 R* g5 w: h+ m. o# I9 f5 R' R8 y$ T0 h; E

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

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

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

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

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