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

MATLAB调用C程序

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x

# W/ O$ V( A1 i8 v9 ?通过把耗时长的函数用c语言实现,并编译成mex函数可以加快执行速度。% M# T! {7 C; u( V
8 H$ Y+ L8 ~7 s8 s
Matlab本身是不带c语言的编译器的,所以要求你的机器上已经安装有VC,BC或Watcom C中的一种。
6 d* `& \' K+ B5 |, ?5 G$ }
" }( C  C% Z, V如果你在安装Matlab时已经设置过编译器,那么现在你应该就可以使用mex命令来编译c语言的程序了。9 I% ^$ b3 _2 _1 n0 e

8 T% o* x1 ^$ l9 U& E9 ~如果当时没有选,就在Matlab里键入mex -setup,下面只要根据提示一步步设置就可以了。# A: n3 C9 V+ [* K5 f6 w
/ L# U7 m# A; h7 q$ l3 ~* X0 s
- u8 S; C0 W' v  x2 ]0 F
0 s0 z$ F, b! ~4 |( m2 \! U. M
为了测试你的路径设置正确与否,把下面的程序存为hello.c。
& Z% C7 M% O; o+ _9 b/ h0 r
4 O4 l7 E. X6 U  @/ c; Z7 D! v5 ??% K! p4 C7 ^' i, T! P" I
/*hello.c*/
4 N' X! @2 [) a#include "mex.h"
; c% h0 E# Q# W2 S3 Y2 wvoid mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])8 }1 K5 a7 ?- s6 ?
{ mexPrintf("hello,world!/n");% n" {+ N; U/ \
}
4 ^* x3 _& y- ^# h4 B) O 假设你把hello.c放在了C:/TEST/下,在Matlab里用CD C:/TEST/ 将当前目录改为C:/ TEST/(注意,仅将C:/TEST/加入搜索路径是没有用的)。现在敲:! X6 ?, r, {( B8 Z. C* A) |
mex hello.c + m$ {1 T3 _( {! |( T* |0 L
如果一切顺利,编译应该在出现编译器提示信息后正常退出。如果你已将C:/TEST/加入了搜索路径,现在键入hello,程序会在屏幕上打出一行:  L$ n% R% k3 B- C# L
hello,world! . c# J% f( w- u6 d

5 V6 F; t4 H8 h$ r0 \整个程序由一个接口子过程 mexFunction构成。9 z8 q' _# }+ `/ ^
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 5 j8 J8 T  g4 ?# K
前面提到过,Matlab的mex函数有一定的接口规范,就是指这
9 b% y( `8 |6 ^$ [2 B# O2 c# bnlhs:输出参数数目 $ N. s9 E8 F. ^' {' o6 S4 N
plhs:指向输出参数的指针
  h- A6 M( K; p: e. Anrhs:输入参数数目
5 @. `: [+ n8 a& W) f例如,使用8 m/ B/ q! O4 |5 r4 C
[a,b]=test(c,d,e)7 q2 L7 [; l; ]/ j
调用mex函数test时,传给test的这四个参数分别是, Q  c, D, ?: E# s7 S* R2 I8 `& l
      2,plhs,3,prhs. m) d' |5 Q+ k( ?8 A7 @
其中: 5 P# ^5 f7 G6 a2 r
prhs[0]=c + Q, N4 X, a9 V5 F7 o* r& R
prhs[1]=d
/ X, w! ~4 F  C3 o% z& L# Bprhs[2]=e
. ^  a2 ~8 l: Q3 W) m2 h当函数返回时,将会把你放在plhs[0],plhs[1]里的地址赋给a和b,达到返回数据的目的。  
& O( c8 f' r- A/ f细心的你也许已经注意到,prhs和plhs都是指向类型mxArray类型数据的指针。 这个类型是在mex.h中定义的,事实上,在Matlab里大多数数据都是以这种类型存在。当然还有其他的数据类型,可以参考Apiguide.pdf里的介绍。
2 L5 i) D+ i1 j$ S/ e$ z* ^6 y7 l$ H2 n9 q& J* Z% ], I' s! q

8 j9 M6 T8 T! r6 g6 }
# X% N! u. _% h//hello.c 2.0 ( z2 f! b* I1 e7 }- E0 O
#include "mex.h" + W; c( U' L6 G) F( T
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
1 W# {  m" F7 ^+ n5 F{
% R" a% r9 l7 r. a1 q! Oint i;
5 X/ u; Y7 R+ W% _0 X( ^i=mxGetScalar(prhs[0]);
8 I  M6 ?- v8 ?0 bif(i==1)
# O1 X! Y2 \6 g( k! v# l( ]0 ^: [  mexPrintf("hello,world!/n");
: g8 a& E9 Y7 b' v4 z6 s6 N7 A. selse 5 r9 }# g5 a9 [8 d
  mexPrintf("大家好!/n"); 4 J- F6 r( t5 {
}5 c; \* E7 K) w  ~; |

+ z( w# v9 q- q% Y; A, @/ F4 y$ D3 e8 F; r" C7 `
将这个程序编译通过后,执行hello(1),屏幕上会打出: hello,world! " {7 n2 w  w7 @% m( X% R. U
而hello(0)将会得到: 大家好!
2 t8 q, ]* l, {+ A" r" a9 t0 L, I+ h. A+ Z( V: o7 w& ?
用到了一个函数:mxGetScalar,调用方式如下:
5 ^2 f4 k/ N; |1 j( y& j1 H8 b# o   i=mxGetScalar(prhs[0]);
4 J! x. R3 {+ c) F% h) u1 h# {"Scalar"就是标量的意思。在Matlab里数据都是以数组的形式存在的,mxGetScalar的作用就是把通过prhs[0]传递进来的mxArray类型的指针指向的数据(标量)赋给C程序里的变量。这个变量本来应该是double类型的,通过强制类型转换赋给了整形变量i。
8 Z% G7 r8 c( P- \" A' @: o4 l4 @# L1 V7 p# O

4 X! {8 H8 H4 N) h
- @% f" g* P& h  f. u//hello.c 2.1
& @$ i* u9 I- X& G. |7 L#include "mex.h"
5 a) x$ A% R, Uvoid mexFunction(int nlhs, mxArray *plhs[],
& H4 c4 r- a% ^3 i0 }int nrhs, const mxArray *prhs[])
! I) Y! k& M1 P, @1 p; p{
4 f+ h, Q. o! K6 g; w& \int *i;
/ e) l, Y, L* ~% v+ L; j3 Qi=mxGetPr(prhs[0]);
" l5 U" d; r: p+ j& L& t& X$ Bif(i[0]==1) % H+ b( U- J8 F5 o( g. B3 J2 x2 Z
  mexPrintf("hello,world!/n"); 3 O+ p: C6 {% r" M( A! N  t" O
else
& e6 x8 r, t: U7 R& V6 A. f  mexPrintf("大家好!/n");
0 w- ^8 r' G. W5 M4 ~/ }2 R}
& L8 ^& W- H( G$ ?* B. K. G% b& ~9 i' F" d& Z. _' j) I

% C; b: ^- R$ N+ \& L( S9 k+ B% d- ?" B$ ~( n& j
这样,就通过mxGetPr函数从指向mxArray类型数据的prhs[0]获得了指向double类型的指针。
% a, |1 ?( F+ C8 z# I7 y但是,还有个问题,如果输入的不是单个的数据,而是向量或矩阵,那该怎么处理呢 ?通过mxGetPr只能得到指向这个矩阵的指针,如果我们不知道这个矩阵的确切大小,就 0 g" S. X4 f- l& H/ f0 ]
没法对它进行计算。
- f) H, s. E7 w3 i. V+ L, O为了解决这个问题,Matlab提供了两个函数mxGetM和mxGetN来获得传进来参数的行数 和列数。下面例程的功能很简单,就是获得输入的矩阵,把它在屏幕上显示出来:
8 H8 y2 Y& V7 S# K! C9 @! y5 p( V: t, T
, Z  a& W6 K- x7 p# {
//show.c 1.0
! B( \$ @+ F# }#include "mex.h"
5 S1 Q! V( n" P% j#include "mex.h" 1 Y% \$ S0 W: r% k
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
- H0 B3 d2 F* G$ k5 B, }: a{ 1 ~6 S3 q. i1 k: v6 `0 H
double *data; ! ]9 P5 M; j5 ~2 B8 E8 _/ B/ `
int M,N; 3 `* r- M; G) ]
int i,j;
' U6 i6 {' ~! g: A* d$ K$ P: R( [( {data=mxGetPr(prhs[0]); //获得指向矩阵的指针 8 v1 K8 ]5 L3 ^& [/ W+ Y. t/ j
M=mxGetM(prhs[0]); //获得矩阵的行数
/ `! h5 w# H: t! k: g" t& YN=mxGetN(prhs[0]); //获得矩阵的列数 . T" ^9 G8 X# o3 t8 y. \4 Q2 _- D5 z$ u
for(i=0;i<M;i++)
6 j; g$ B& a1 F5 f6 I9 ^{   for(j=0;j<N;j++)
% v& K! t1 \. t( Y$ @( Q% X     mexPrintf("%4.3f  ",data[j*M+i]);
8 `  L1 ^9 G( e. A( }     mexPrintf("/n"); 7 l. p. @% m. g
  }( o4 w4 Y. {, l5 ]
}
( b1 r, v. T8 w" t! m
& N: A5 k* J7 `/ N+ }" |6 s0 Q4 A: C! k
7 O* m% b  B0 V" O5 r' M( P: C, R9 }: \
编译完成后,用下面的命令测试一下:
+ ?2 S% ~& I1 `' F/ r; M! z$ [  a=1:10;
! |( [* y: H' A! D  b=[a;a+1];
- z( U( m! K3 d' B  show(a)   X4 H# X. b* z
  show(b)
3 l2 G; x4 F6 K; J6 k需要注意的是,在Matlab里,矩阵第一行是从1开始的,而在C语言中,第一行的序数为零,Matlab里的矩阵元素b(i,j)在传递到C中的一维数组大data后对应于data[j*M+i] 。
& M+ i+ u5 V3 k: e& I. g输入数据是在函数调用之前已经在Matlab里申请了内存的,由于mex函数与Matlab共用同一个地址空间,因而在prhs[]里传递指针就可以达到参数传递的目的。但是,输出参数却需要在mex函数内申请到内存空间,才能将指针放在plhs[]中传递出去。由于返回指针类型必须是mxArray,所以Matlab专门提供了一个函数:mxCreateDoubleMatrix来实现内存的申请,函数原型如下:
; k! o" L* N0 U4 U   mxArray *mxCreateDoubleMatrix(int m, int n, mxComplexity ComplexFlag)
7 P: K- u. C/ m/ w   m:待申请矩阵的行数 3 `) x% s: m$ u4 L' M2 `  o1 t
   n:待申请矩阵的列数 8 L: b  g7 w* a6 Z
为矩阵申请内存后,得到的是mxArray类型的指针,就可以放在plhs[]里传递回去了。但是对这个新矩阵的处理,却要在函数内完成,这时就需要用到前面介绍的mxGetPr。使用 mxGetPr获得指向这个矩阵中数据区的指针(double类型)后,就可以对这个矩阵进行各种操作和运算了。下面的程序是在上面的show.c的基础上稍作改变得到的,功能是将输  
7 s& A6 a" c* k. `3 l
) C5 [' `' G; b 6 Y9 O% g9 l% q

( k0 s8 A# C  f( h
3 F4 g! k" e2 o' }1 [9 [+ h//reverse.c 1.0 8 B. l6 ?9 S6 z& R: K/ ?
#include "mex.h"
+ F' A! J% l$ y1 i7 u4 G" bvoid mexFunction(int nlhs, mxArray *plhs[],
# E6 w$ l+ c$ Y& G6 C1 {    int nrhs, const mxArray *prhs[])
$ A( m9 i5 J# o9 c0 x! i% `' c{
% R* A/ `4 e9 Ydouble *inData; ; g; t' i; c' m: P2 ^6 x6 q) r
double *outData;
* V" r' F) T: u  i# Mint M,N;
( ]7 |, |5 i4 S$ pint i,j;
" Y- `5 e2 l& q4 zinData=mxGetPr(prhs[0]); - P% r( R& \8 ^9 L" O3 r1 K
M=mxGetM(prhs[0]); ( o9 A* J# E1 X1 T9 w, x3 Z( D
N=mxGetN(prhs[0]); ) I- F3 Y5 L0 D' g7 E; A
plhs[0]=mxCreateDoubleMatrix(M,N,mxREAL);
! z9 `7 F7 X+ [; \; |outData=mxGetPr(plhs[0]);
. }8 _" s! J9 v* ?for(i=0;i<M;i++) % @7 D* r& P5 Z' p0 a- p
  for(j=0;j<N;j++)
0 L9 e6 H+ W7 B- F   outData[j*M+i]=inData[(N-1-j)*M+i]; , N  y; N7 t6 W5 d3 S9 j) M1 {$ m5 ~& ^
} / d3 Q8 M% Y% o
& A! M) P0 u& P: H5 H

1 `6 Z1 l  v" f! e5 ?6 x' Z- `
8 z/ P8 E( b5 P% i  Y当然,Matlab里使用到的并不是只有double类型这一种矩阵,还有字符串类型、稀疏矩阵、结构类型矩阵等等,并提供了相应的处理函数。本文用到编制mex程序中最经常遇到的一些函数,其余的详细情况清参考Apiref.pdf。
; Q- q0 P% k7 r3 {通过前面两部分的介绍,大家对参数的输入和输出方法应该有了基本的了解。具备了这些知识,就能够满足一般的编程需要了。但这些程序还有些小的缺陷,以前面介绍的re由于前面的例程中没有对输入、输出参数的数目及类型进行检查,导致程序的容错性很差,以下程序则容错性较好
0 Y. c0 T4 w1 e! O
7 s% z( c: ~, y! S% L/ F: H0 n7 L/ N2 e4 Q& e
#include "mex.h"
6 G& A% z6 P/ B* Q  Zvoid mexFunction(int nlhs, mxArray *plhs[],  int nrhs, const mxArray *prhs[])
5 b' x2 Y, B  M" K& `{
8 `; m( H- Y8 Q$ ndouble *inData; 3 ^8 m; ^( T3 |8 d9 C
double *outData;
. V( T7 z  W0 bint M,N; , \" j% L) O/ F/ `2 b
//异常处理
4 `) X+ A0 S: v! K5 f9 E5 \: o  X; N//异常处理
% w7 r- c; ~# |1 c+ t$ G2 p' kif(nrhs!=1) 8 \# {0 }( b3 j' c
    mexErrMsgTxt("USAGE: b=reverse(a)/n");
4 m  B7 Q/ l0 y5 P* z" ^" Q- r4 v  if(!mxIsDouble(prhs[0])) : t% `. D! g7 U: e) y+ j, l
   mexErrMsgTxt("the Input Matrix must be double!/n");
( k, i  Z1 U* `+ {7 |   inData=mxGetPr(prhs[0]); 2 `; I( Q" D0 D9 A
   M=mxGetM(prhs[0]); 2 i. m) i5 X; ]1 D* R2 o8 U
   N=mxGetN(prhs[0]);
4 V- S7 u; M1 H+ l# E4 }0 V6 g   plhs[0]=mxCreateDoubleMatrix(M,N,mxREAL);
& g# X% G( B  T  H' O) Q   outData=mxGetPr(plhs[0]);
+ x3 V) K5 c4 P5 l" Z$ l. K   for(i=0;i<M;i++) ( g% v/ M& n- l4 N2 }, C
     for(j=0;j<N;j++)
6 O' m/ S. J# [( q3 N% V- W     outData[j*M+i]=inData[(N-1-j)*M+i]; 3 i& d; T# a3 E+ i6 n
  }
  L" {0 H+ t$ \; o$ D. W) S, D/ c' U( J* l  f$ u1 A8 _
* e- E- q  b. ?

: g/ }* [# c3 _) y在上面的异常处理中,使用了两个新的函数:mexErrMsgTxt和mxIsDouble。MexErrMsgTxt在给出出错提示的同时退出当前程序的运行。MxIsDouble则用于判断mxArray中的数据是否double类型。当然Matlab还提供了许多用于判断其他数据类型的函数,这里不加详述。
, l1 G' p9 c, b需要说明的是,Matlab提供的API中,函数前缀有mex-和mx-两种。带mx-前缀的大多是对mxArray数据进行操作的函数,如mxIsDouble,mxCreateDoubleMatrix等等。而带mx前缀的则大多是与Matlab环境进行交互的函数,如mexPrintf,mxErrMsgTxt等等。了解了这一点,对在Apiref.pdf中查找所需的函数很有帮助。  C8 r: x+ N: ]" o# {# N- `
至此为止,使用C编写mex函数的基本过程已经介绍完了。 : F/ `* Y$ t: `; |) P4 \8 N2 N, @
" U- w9 F- u( f

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-7-23 22:12 , Processed in 0.125000 second(s), 23 queries , Gzip On.

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

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

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