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

MATLAB调用C程序

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
2 y$ ?5 m' L% |1 U# O* h# z! Y
通过把耗时长的函数用c语言实现,并编译成mex函数可以加快执行速度。. \" E/ y" o, O+ C( s

8 I: `2 \1 H2 J! l( |3 JMatlab本身是不带c语言的编译器的,所以要求你的机器上已经安装有VC,BC或Watcom C中的一种。
+ V9 ~3 ~5 D/ {4 {* T. n/ ]4 ]8 I+ k% K0 T# ^5 _1 q
如果你在安装Matlab时已经设置过编译器,那么现在你应该就可以使用mex命令来编译c语言的程序了。
7 N1 V" f+ c  @9 V
+ z8 k1 \) b6 v. r% ~如果当时没有选,就在Matlab里键入mex -setup,下面只要根据提示一步步设置就可以了。
& N. k  w; Z( I1 `3 h8 O2 B5 `% m, e" Y4 n: ?

) c  k6 e% ~4 V0 ~: O3 p: r" Z8 t" [$ @* |' n* f
为了测试你的路径设置正确与否,把下面的程序存为hello.c。
- s7 l7 ]  b! Q* I& C2 K' Y
+ }/ W4 b& H& k# e$ ~?: k6 c: m7 D0 }$ @2 U4 j
/*hello.c*/
0 l; c( {$ K( d$ Z#include "mex.h"
, K4 ?7 M6 z0 f/ z$ U: pvoid mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
5 K# \% {$ h( T' x$ C# T{ mexPrintf("hello,world!/n");
2 b# r  }6 O( r4 I) M}
' e4 F- ?6 `. G5 f4 Z2 @, O 假设你把hello.c放在了C:/TEST/下,在Matlab里用CD C:/TEST/ 将当前目录改为C:/ TEST/(注意,仅将C:/TEST/加入搜索路径是没有用的)。现在敲:) L' ?9 ]2 t0 l7 T- g/ v
mex hello.c
! }& E6 T* c- Z! T如果一切顺利,编译应该在出现编译器提示信息后正常退出。如果你已将C:/TEST/加入了搜索路径,现在键入hello,程序会在屏幕上打出一行:" |* d) p3 g. w
hello,world! ) a0 l  C, I1 o! R

- g" `4 `. ^8 @  z, u' [整个程序由一个接口子过程 mexFunction构成。
- X7 ?  L, G6 n' `1 u" k) ovoid mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
1 I3 Z/ ~8 k7 e. q, i, F4 r前面提到过,Matlab的mex函数有一定的接口规范,就是指这
+ g- z2 f* ?) o$ u3 ^nlhs:输出参数数目 ( b7 M! u9 k5 K4 L- Y" S$ k
plhs:指向输出参数的指针
; [+ b0 ?4 @' ^  I- K4 e, {2 mnrhs:输入参数数目
- H: O5 I$ H- v" z# Z7 S例如,使用! t9 t  L2 L6 M7 Q6 t) T
[a,b]=test(c,d,e)
) }3 ~+ y4 o0 p" f' g, ], j调用mex函数test时,传给test的这四个参数分别是
- b0 y" g2 H/ c, d      2,plhs,3,prhs3 M: a5 B# F% D
其中:
; B& r5 p" m; F! ^# \prhs[0]=c
3 P# _) B% V2 q' Jprhs[1]=d
6 Q* [2 C/ _  V/ n. ~prhs[2]=e % m% p1 @  r5 H; m6 P
当函数返回时,将会把你放在plhs[0],plhs[1]里的地址赋给a和b,达到返回数据的目的。  
0 [: C% a% l7 {3 v" n1 l细心的你也许已经注意到,prhs和plhs都是指向类型mxArray类型数据的指针。 这个类型是在mex.h中定义的,事实上,在Matlab里大多数数据都是以这种类型存在。当然还有其他的数据类型,可以参考Apiguide.pdf里的介绍。 . o) i  |  c0 c

* v8 ^3 [( {1 ^ ' s  t% T4 O. S( R

% a) y# Y! e# R9 y9 S" b$ K//hello.c 2.0
- }" Z( L. U$ n7 o7 ^  E. W& W#include "mex.h"
/ Q9 Q6 P- W! f/ `void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
. p- @, l: P8 _- U5 T: I5 y+ N{
) k7 M8 r0 ?" X4 qint i;
2 p/ ?9 j' [9 L& ~, Bi=mxGetScalar(prhs[0]); & q  N- W$ ~* Y/ L# p
if(i==1)
6 ]! p5 V4 D5 e  mexPrintf("hello,world!/n"); 8 `. Z6 i; e1 W( @
else
3 {' {& [' O1 n" F3 o  mexPrintf("大家好!/n");
7 k% v0 {4 \  T/ }( \. q+ R}, [$ s) a3 x7 T
3 B) E" f, S  E* M) \
' t. ^+ |# V# U3 q$ @
将这个程序编译通过后,执行hello(1),屏幕上会打出: hello,world! 7 T4 C4 \% r. L) Y: Z  g* H( A
而hello(0)将会得到: 大家好!( V& i5 m) s+ g4 ~/ s4 G7 Z
% W. j; D& r* R+ I, e) t# ]! J
用到了一个函数:mxGetScalar,调用方式如下:
0 @" |8 y6 \! F% _; s) m* f   i=mxGetScalar(prhs[0]); 9 o1 _- `# d* b
"Scalar"就是标量的意思。在Matlab里数据都是以数组的形式存在的,mxGetScalar的作用就是把通过prhs[0]传递进来的mxArray类型的指针指向的数据(标量)赋给C程序里的变量。这个变量本来应该是double类型的,通过强制类型转换赋给了整形变量i。
% h) u! @7 t/ T' y7 g
: p% E8 s9 n  ^# F / {7 e& a. J3 C! [
) N; z2 J4 E0 }$ x4 w
//hello.c 2.1
- s; O8 c4 x: P" A$ G3 n#include "mex.h"
. f9 e) ~6 ?0 x; {5 ~void mexFunction(int nlhs, mxArray *plhs[], 1 B+ g& A4 A1 S+ N' S0 V
int nrhs, const mxArray *prhs[]) ; K% t7 e7 J4 m/ H- M& R: ~- V4 n; r
{ 4 ]  Y: u$ [) a$ [6 @- x
int *i; & }! W7 T+ c& W! N- H7 t
i=mxGetPr(prhs[0]);
- K7 X/ H0 B& W6 `' m+ W3 p" hif(i[0]==1) : t, `% L- F) ~( p/ Z
  mexPrintf("hello,world!/n");
8 X' E7 {: ~$ `; C$ z8 ]5 qelse " B4 ~9 u7 M/ x# h2 i4 m
  mexPrintf("大家好!/n");
0 W0 ]* {" Y' d$ F/ r} # m5 n* M+ v, Y2 Q5 i
* t8 H" C" S" W" U

9 O$ L$ k4 x. W9 [3 k
/ ]/ Z% B8 H6 i* o这样,就通过mxGetPr函数从指向mxArray类型数据的prhs[0]获得了指向double类型的指针。1 ~; o  l; ?  x' I9 N' L
但是,还有个问题,如果输入的不是单个的数据,而是向量或矩阵,那该怎么处理呢 ?通过mxGetPr只能得到指向这个矩阵的指针,如果我们不知道这个矩阵的确切大小,就
5 \) O* I, B0 {5 k, i, ^没法对它进行计算。
. O& b& C) a7 h& z! J/ f+ p5 ?为了解决这个问题,Matlab提供了两个函数mxGetM和mxGetN来获得传进来参数的行数 和列数。下面例程的功能很简单,就是获得输入的矩阵,把它在屏幕上显示出来: 7 M9 a/ ^) W6 g  ~2 t

" {4 p, l5 \8 n/ d- V  i0 k6 x: n9 \- I, E2 o. x/ h
//show.c 1.0 : x, Z1 Y) \; c0 G7 _+ ^7 n( ]
#include "mex.h" ' `. [- U  E% Z
#include "mex.h" 4 E( Y- s% i0 ]7 L& G; u- h
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
1 x4 ~6 E4 e) X) D: k{ 2 b% L9 r/ h, E. V/ {, u: G
double *data; . `: }/ |3 w3 B1 w) \7 l+ z  N
int M,N;   [, M6 I7 v. w& g
int i,j;
. q. ^- P; }9 d. Zdata=mxGetPr(prhs[0]); //获得指向矩阵的指针
: n  S# X+ o) V8 hM=mxGetM(prhs[0]); //获得矩阵的行数 ( f4 P9 c) I0 ~* S/ j
N=mxGetN(prhs[0]); //获得矩阵的列数
8 ?" r0 q$ B9 A1 Nfor(i=0;i<M;i++)
8 _) o0 g' \& a6 ~" k9 P{   for(j=0;j<N;j++)
" }. W( i0 M* r5 w/ V  B6 r5 I( Y% B     mexPrintf("%4.3f  ",data[j*M+i]); 8 b$ K# D5 ?6 H$ x
     mexPrintf("/n"); 0 v* m5 `/ s4 q8 ~4 \
  }
5 }( z3 h! V% G; Q4 r  w  ~5 m}
; G" G" ^; R0 B! ^
! H( i+ Y; G, X3 `- z2 v+ i: F 2 B9 I$ k2 C7 \  D" {1 P4 N
8 ^$ l! [5 V  J6 ]; x$ i
编译完成后,用下面的命令测试一下: # K7 z+ Z% M6 F# U4 \+ s1 U8 i
  a=1:10; ' M: K4 n& k/ k* p3 s3 a
  b=[a;a+1];
* u4 [9 ?+ z, A& U2 a3 E: V% `# X3 w4 O  show(a)
) p; g: [( {2 l. I& U2 b  show(b)
: R" H  D+ Y, j需要注意的是,在Matlab里,矩阵第一行是从1开始的,而在C语言中,第一行的序数为零,Matlab里的矩阵元素b(i,j)在传递到C中的一维数组大data后对应于data[j*M+i] 。
9 ?+ `1 s) T) ]$ _3 W& z5 g输入数据是在函数调用之前已经在Matlab里申请了内存的,由于mex函数与Matlab共用同一个地址空间,因而在prhs[]里传递指针就可以达到参数传递的目的。但是,输出参数却需要在mex函数内申请到内存空间,才能将指针放在plhs[]中传递出去。由于返回指针类型必须是mxArray,所以Matlab专门提供了一个函数:mxCreateDoubleMatrix来实现内存的申请,函数原型如下: " |! |2 [3 T- w! {6 _& B0 J% r/ D
   mxArray *mxCreateDoubleMatrix(int m, int n, mxComplexity ComplexFlag)
7 @5 q& k0 D4 W5 l3 w/ R" C# u) C4 t+ n) v   m:待申请矩阵的行数 ! k0 D5 g! z4 I8 A
   n:待申请矩阵的列数
: n; b8 O7 K1 Z/ |% O为矩阵申请内存后,得到的是mxArray类型的指针,就可以放在plhs[]里传递回去了。但是对这个新矩阵的处理,却要在函数内完成,这时就需要用到前面介绍的mxGetPr。使用 mxGetPr获得指向这个矩阵中数据区的指针(double类型)后,就可以对这个矩阵进行各种操作和运算了。下面的程序是在上面的show.c的基础上稍作改变得到的,功能是将输  
( |- g& N, j3 w
% p# o" R, K0 M; c+ ~6 y # m3 v% y( B, k' d/ ~$ }
. V" G- {9 q& [9 n5 q
5 ^& W7 U* G3 R% b0 h
//reverse.c 1.0
/ F& \2 L% H  y+ E#include "mex.h"
2 j! v" l$ P9 avoid mexFunction(int nlhs, mxArray *plhs[], % S9 z( {* s2 R' C
    int nrhs, const mxArray *prhs[]) * V) x  B0 Y# c4 ]$ }% j
{ # g8 w0 M8 d! R$ P  `9 @
double *inData;
8 r6 P0 J+ I8 `: O& ?8 v6 Ddouble *outData; / ~2 Z! p; R( B- [/ @
int M,N;
  ?! h1 @( j9 Pint i,j; ' J7 Y# `, v4 a7 y# R
inData=mxGetPr(prhs[0]);
1 z# X9 N, J5 }  _: l9 lM=mxGetM(prhs[0]);
/ K' V& v& X6 A0 aN=mxGetN(prhs[0]); 1 r0 F  h! h% w& Q2 u0 N3 j
plhs[0]=mxCreateDoubleMatrix(M,N,mxREAL);
. U: \" n8 s, e, coutData=mxGetPr(plhs[0]);
* z/ X8 k$ r7 A; Z9 u; x. ]$ Jfor(i=0;i<M;i++)
' b% Q/ s8 g, u  for(j=0;j<N;j++)
" Z& @8 Y  H7 E+ _* p( K) ]   outData[j*M+i]=inData[(N-1-j)*M+i]; 9 t7 P: P- }+ n
} ( [4 B* U2 ]! B' R" a# \$ d. `% R
; T6 M9 a, _6 D, j1 s2 y) N
* D) V' h- N4 g! d0 [8 f" R

" }2 D7 O$ ~, A5 h当然,Matlab里使用到的并不是只有double类型这一种矩阵,还有字符串类型、稀疏矩阵、结构类型矩阵等等,并提供了相应的处理函数。本文用到编制mex程序中最经常遇到的一些函数,其余的详细情况清参考Apiref.pdf。 ) O  R; m/ i* N8 ^+ H8 s* E
通过前面两部分的介绍,大家对参数的输入和输出方法应该有了基本的了解。具备了这些知识,就能够满足一般的编程需要了。但这些程序还有些小的缺陷,以前面介绍的re由于前面的例程中没有对输入、输出参数的数目及类型进行检查,导致程序的容错性很差,以下程序则容错性较好/ T4 y# r5 U" o' f6 d! Q
2 h) T. b) E; t

, z$ c" O7 G& H% v# p4 b#include "mex.h" 6 x/ x; ~3 h$ c. O& G$ N2 j1 [9 g  i
void mexFunction(int nlhs, mxArray *plhs[],  int nrhs, const mxArray *prhs[])
9 Q" z2 \4 o8 a1 v& F& k# x, c5 q{
# L) ~5 J0 i, J" }: k; f+ Edouble *inData;
, K6 ~, T9 m& odouble *outData;   a0 z8 I" R, ?# O- X) A* b; l
int M,N;
5 O" C0 [$ g2 m  ^5 f3 u! J+ X//异常处理 * A5 h) u" V2 z/ H) u
//异常处理 ; c7 Z( n6 [, l1 F. K
if(nrhs!=1)
: V: A& C$ |" k3 @+ d! a- H* |    mexErrMsgTxt("USAGE: b=reverse(a)/n"); ! _) U3 r1 W; ^8 L2 b5 F& k
  if(!mxIsDouble(prhs[0]))
- c$ j6 `$ b1 ~5 e" e( ]   mexErrMsgTxt("the Input Matrix must be double!/n"); ) _+ \8 t! I( u
   inData=mxGetPr(prhs[0]); : q% Q8 J7 d  {4 x$ m
   M=mxGetM(prhs[0]);
: h6 H0 z  B8 S) S0 G5 ?$ C   N=mxGetN(prhs[0]); - j8 s% T0 R5 D) a2 {6 Q
   plhs[0]=mxCreateDoubleMatrix(M,N,mxREAL); ( e4 \3 @  ~  E$ o
   outData=mxGetPr(plhs[0]); - }3 R+ e9 F( `
   for(i=0;i<M;i++)
9 \7 r7 o$ }% h  D4 c8 F! F     for(j=0;j<N;j++)
" q1 N+ R) {% K5 x  M     outData[j*M+i]=inData[(N-1-j)*M+i]; 7 S+ d. z2 B5 C) |
  }
' k6 w5 ]/ W0 K+ }2 i7 K: V5 b( w+ u
6 G" W6 W% r- Y: D1 _2 `
& ^4 C& U2 W' W7 R' b" l: _. g9 G0 Z, {* D
在上面的异常处理中,使用了两个新的函数:mexErrMsgTxt和mxIsDouble。MexErrMsgTxt在给出出错提示的同时退出当前程序的运行。MxIsDouble则用于判断mxArray中的数据是否double类型。当然Matlab还提供了许多用于判断其他数据类型的函数,这里不加详述。   a: Y2 O; O. W5 ~* X+ ^
需要说明的是,Matlab提供的API中,函数前缀有mex-和mx-两种。带mx-前缀的大多是对mxArray数据进行操作的函数,如mxIsDouble,mxCreateDoubleMatrix等等。而带mx前缀的则大多是与Matlab环境进行交互的函数,如mexPrintf,mxErrMsgTxt等等。了解了这一点,对在Apiref.pdf中查找所需的函数很有帮助。
$ m! x& e* @& \8 t0 L* [; e4 ~' s至此为止,使用C编写mex函数的基本过程已经介绍完了。 0 l/ ]! y3 O" V( M$ ]& E
. E" T/ {) ]( f- [, Z3 E5 G3 L8 Z( c- I9 p

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

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

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

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

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