TA的每日心情 | 怒 2019-11-20 15:22 |
|---|
签到天数: 2 天 [LV.1]初来乍到
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
, i" |! o7 h6 x0 Z
用C编写mex程序( T: l- n2 B* e0 @3 T
大家都知道,matlab是一种解释型的编程环境,也就是说,跟以前的basic一样,是读
% P# f+ U1 v; {/ `- B& ]一句执行一句的。这样做可以很方便的实现编程过程中的交互,也免去了麻烦又耗时的 J/ c* u# `' n: R
编译过程。但凡事有一利必有一弊,matlab在执行时速度慢也就根源于此。在matlab里
, }2 T' |! h7 n( @5 |2 q3 m tic9 f! W* t+ W' M& `! T
for i=1:10000: C* c1 \6 A9 F8 D4 V8 z
b(i)=a(10001-i);
% F; X: a" i- j! Z/ W7 w! x2 B end
6 K+ P( b7 D/ U. `) c# K( N 怎么样,是不是很慢?
8 i3 p1 \5 Y! U$ i# q' a$ g/ P" ]8 V 你的程序里如果再多几个这样的循环,运行速度就可想而知了。
4 z* M" ~! q9 `0 O 上面程序的功能是将向量a里的数据逆序赋给向量b。下面的程序可以实现相同的功能, u% K( K0 z# L) k+ ]7 z1 x
tic$ x' f3 q8 B* z
b=a(10000:-1:1);
8 d6 `/ s. g: i" T$ H( C 为什么这个程序运行速度就这么快呢?这是因为matlab里的基础矩阵运算函数,像转
! [2 O- d4 P( l* L, v$ I& H# M( A置,复制等等,都是以二进制程序的形式存在的,运行起来速度当然比解释执行10000次
p! i, l* i+ S 所以编matlab程序时,应该尽量避免用循环语句,而使用等效的矩阵运算。虽然这样
! q. T& ~4 y, Q1 i) @9 I 但总是有的时候没法找到对应的矩阵运算来等效,或编出来的程序复杂得让人没法修/ j$ V- A0 [& L, T/ S! C- S% y+ K
简单地说,mex程序就是根据一定的接口规范(mtlab提出的)编写的一个dll,matla5 A6 f% V4 r8 M0 S* ?$ R( l
比如我编了一个mex函数,名字叫max2.dll,那么只要把这个dll所在的目录加到matlab" B+ N1 W3 [5 w
的搜索路径里(用addpath),就可以像调用普通matlab函数一样来调用它了。因为把
& e x% _( s) m& P( [! x1 t. x( L" b. ^+ L
循环体放到了二进制程序中,执行速度快得多。$ n9 p! R( \ A4 v4 Z! n- ~
) Q" `7 `1 `3 x. y8 F$ ~
8 }9 Q2 c0 v/ ]% r; k9 s' l Mex文件既可以用c,也可以用fortran来编。因为我用的是c语言,所以下面的介绍都4 j( b/ k; J, Y; f
& A5 x8 d1 \# J# t- C* L7 p) C是用c语言编写mex文件的方法。如果你用的是fortran,请你自己去看Apiguide.pdf,里
6 J2 W- p0 e1 H9 c3 y; r) o: u0 p3 e. ?) @! e
面有详细说明。* v% f4 i7 g* n8 N0 M# @2 I- V
: b2 m F; u, P' H8 D
前面说到通过把耗时长的函数用c语言实现,并编译成mex函数可以加快执行速度。这& R# C) f. `# @$ ^9 E
Matlab5.1本身是不带c语言的编译器的,所以要求你的机器上已经安装有VC,BC或Wat* s# E0 s: s% ]) B( x- N& \
com C中的一种。如果你在安装Matlab时已经设置过编译器,那么现在你应该就可以使用
) I& t9 }( z. h+ S8 b( o# f4 Emex命令来编译c语言的程序了。如果当时没有选,只要在Matlab里键入 mex -setup" b; V! I d3 F* c' c& j! T
,就会出现一个DOS方式窗口,下面只要根据提示一步步设置就可以了。由于我用的是w
. k( r8 q$ Z4 s v7 S 听说Matlab5.2已经内置了C语言的编译器,那么下面的这些可能就用不着了。可惜现/ }& t* o8 o) P l$ p; Z" ~4 t$ Z
需要注意的是,在设置编译器路径时,只能使用路径名称的8字符形式。比如我用的V6 P; Y5 {( f( `1 z% e9 w3 |
C5装在路径 C:\PROGRAM FILES\DEVSTUDIO下,那在设置路径时就要写成:C:\PROGRA~15 W1 I$ q; {) r2 K T( }3 A
这样设置完之后,mex就可以执行了。为了测试你的路径设置正确与否,把下面的程序
0 Y1 `( {2 g1 g/ ~8 G存为hello.c。8 T# y+ @" K3 ^7 n
! P: |5 P% q5 G. `8 C8 Q. V
7 U0 ^9 F' d7 v) {7 C1 C8 d#include "mex.h"2 N r& H# v9 T: f2 M, u- H
3 M- Z( C* X% f/ j1 o6 k, G
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
* y$ z4 i6 e" U
% P8 W0 d& H, f( X& f9 w( n$ |9 r, V* {0 e! p5 N K3 p
{+ B5 G3 Z- S# g
) E3 p# i3 ]2 r# n* XmexPrintf("hello,world!\n");6 R) s" ^! a6 N# _! {, a
# {: e% E9 l. h+ m}
& Z l6 ~. R6 `# \: ^. P: b" {- X% A! Z7 C: K
) Y3 U1 d, @3 f% `2 B1 z V
假设你把hello.c放在了C:\TEST\下,在Matlab里用CD C:\TEST\ 将当前目录改为C:\
4 @2 h) ~8 y5 j
7 \0 \/ ]; l. B4 T0 I# YTEST\(注意,仅将C:\TEST\加入搜索路径是没有用的)。现在敲:
3 q, m) F1 ^1 }% P& ^4 M3 _) S- f4 S
, Q Z) B: G- A* r; K
mex hello.c7 ?1 J" R% E6 O; _) I( ^
/ B+ {; Y% g8 J* F
$ r2 R, W4 x; |" r$ i& m9 Q 如果一切顺利,编译应该在出现编译器提示信息后正常退出。如果你已将C:\TEST\加
( O3 i* e% t7 N5 P' }, |1 _
6 X! U% r& [/ `; o5 B6 d' l& B入了搜索路径,现在键入hello,程序会在屏幕上打出一行:9 O" Y4 H$ u7 M) e# U7 U
m5 u, a& g7 h- h& m) j. o: V9 U( e1 B2 V7 l5 x# B
hello,world!3 O& j% Q: w: v, A4 v* w) V) F8 L) s' Y
0 K' I: M- V p# Y# J1 ]
; B2 ]; L. K2 |5 v 看看C\TEST\目录下,你会发现多了一个文件:HELLO.DLL。
& q$ V1 m/ ~0 f+ ?
% i% e/ o; ]. B- Q# ~9 h j2 C; [9 T) ]% ?2 Q2 g# t
这样,第一个mex函数就算完成了。怎么样,很简单吧。下一次,会对这个最简单的程! r4 p8 a: n. K
) p( Y2 {6 J: s" s$ R8 X3 ?序进行分析,并给它增加一些功能。
' T& f) v# U8 i: `分析hello.c,可以看到程序的结构是十分简单的,整个程序由一个接口子过程- U! q& _/ y% X1 Y+ ]
mexFunction构成。前面提到过,Matlab的mex函数有一定的接口规范,就是指这
: g, l0 S6 w3 O0 {0 ]! a2 Wnlhs:输出参数数目, c# S* ^) b9 w# r
plhs:指向输出参数的指针* K# o7 A' N0 {' a: D" A
nrhs:输入参数数目
% z/ j$ E* e" |. n& H例如,使用 [a,b]=test(c,d,e) 调用mex函数test时,传给test的这四个参数分别是2,+ S; w, n& ~% t( S5 l& Q
plhs,3,prhs。其中:
. M2 u7 v" x3 Sprhs[0]=c
% Z0 i2 ~( X$ v
* n$ P; j( r; Vprhs[1]=d
* U" t6 J' O* X2 E6 y5 Z, _5 u! a: M. V8 b. S, u. A8 {" C
prhs[2]=e" ]6 x$ n3 f3 n2 G! n
( Z, a) h0 n) P @& E
当函数返回时,将会把你放在plhs[0],plhs[1]里的地址赋给a和b,达到返回数据的目
5 Q7 N" L: g$ `% l5 w- k5 f& R) A$ w, R5 F# C: }' x" y* `
的。
$ x( a/ u% |' ]2 j3 B' W' V* c" v5 ^( N) U3 s! u0 ^* A6 {
7 W$ k$ _# u+ Y$ g/ Y+ E, n 细心的你也许已经注意到,prhs和plhs都是指向类型mxArray类型数据的指针。# N$ n5 x, l* y$ _8 D
7 i+ Z7 k+ O P
这个类型是在mex.h中定义的,事实上,在Matlab里大多数数据都是以这种类型存在。当9 J2 }9 A8 x! X6 V4 q
, u) {4 O6 s. \- _8 l( W, |2 l然还有其他的数据类型,可以参考Apiguide.pdf里的介绍。
7 Z- K. I* c8 P; a o; F9 n3 L# ?6 b4 l" K( j
8 K( P# i2 s+ l: ^
为了让大家能更直观地了解参数传递的过程,我们把hello.c改写一下,使它能根据输$ z+ W; @& C2 x9 \: B
$ E# C) C- X6 D. ]/ t
入参数的变化给出不同的屏幕输出:4 J/ w$ U; A; [0 U. E
6 d0 g+ P' w1 \ C' s2 h* g9 _: X# v6 E+ ?& U
//hello.c 2.0
' h5 Q" N& D2 y, ?( [6 [, A }& U2 O
0 ~6 @/ H: Y, E! ?& a: I- w
#include "mex.h"1 }: r) z( N" t$ I
, M6 d7 g1 `' f; ?. @void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
7 O6 E. T; u+ x* l% w1 V
" S1 c9 d- `; @. Q, l R{: T; ]( z' i" f/ g
5 @! c, Y% K! d! B2 ?, c# E$ tint i;( [4 V3 w( B3 w( ]
& S/ m% j4 m4 A! a2 V
i=mxGetScalar(prhs[0]);
+ h* ]" E6 o& f$ G$ z' _8 w3 a* x1 b- w* G, H+ L3 j/ S* k
if(i==1)
8 S! N4 N7 {# b+ a5 ^0 Y4 O, X3 s' |) e
mexPrintf("hello,world!\n");! g5 w5 F0 E$ [
/ n) i7 p F( {! R- I/ }
else
; c- s6 f' v4 J. [: `2 E8 Y2 S) Q! `% z- i( C* ]$ D2 l
mexPrintf("大家好!\n");' V2 z( k# e4 y( ~
0 ~% i9 q# k( b( u}/ N8 L( ~/ ^! }2 B% B- J( f: }
: n2 v4 ~# O8 [7 b
& N8 I3 ~: `! Y) x3 {! K 将这个程序编译通过后,执行hello(1),屏幕上会打出:3 p% U# ?' G$ U( b
& C, @8 S6 h2 E5 h& Q' s3 v/ x, `hello,world!
- A( d$ p5 X; h$ J, ]) o2 ?/ M( U2 T7 \2 J
而hello(0)将会得到:
, }0 z+ y7 v# y4 t1 {/ [! s0 T
$ G1 C5 O, J6 j! R' A大家好!
$ S: k3 R5 s% [( T* @( q; U
- x* c$ y% S+ M4 |: a, W% D& x) D n0 M
现在,程序hello已经可以根据输入参数来给出相应的屏幕输出。在这个程序里,除了用
# {% s3 S, ]* X: p8 T: t( }2 L+ |) {6 g6 m- j6 j0 {9 d
到了屏幕输出函数mexPrintf(用法跟c里的printf函数几乎完全一样)外,还用到了一4 H% i2 D t1 q! o% K# G# p
9 A* w+ n. n0 V" B6 ]: g; z4 G1 \
个函数:mxGetScalar,调用方式如下:
( a1 u3 k* p; r, U& u- p$ m( ~8 A+ ]
i=mxGetScalar(prhs[0]);
3 P7 k4 o; R2 I# Z- H1 e' ^
4 L8 I' O# Y& D! O "Scalar"就是标量的意思。在Matlab里数据都是以数组的形式存在的,mxGetScalar的8 u! }5 }& C* R' r9 m1 Q7 o
/ B# | ]' Q+ E+ J1 x, F
作用就是把通过prhs[0]传递进来的mxArray类型的指针指向的数据(标量)赋给C程序里0 c y" J! ]: H# z, l+ T+ ~8 p
2 V; I% X. ]- S! j9 j+ L2 J的变量。这个变量本来应该是double类型的,通过强制类型转换赋给了整形变量i。4 q% z0 V8 r; g4 z. T0 M6 l
# Z* n3 s' P" f5 G+ w3 u+ {) G* Q3 Q* L( {: y' ^0 W
既然有标量,显然还应该有矢量,否则矩阵就没法传了。看下面的程序:! O5 `, k1 Z' w7 R$ t8 k, K3 W8 i
2 k3 u' W9 d2 G, i4 l
" E$ P( ], _$ ]0 s7 B//hello.c 2.1
1 f6 z! ^! d3 E" v$ g
3 C1 D$ v' \; \; b n' K2 g& Z. l7 i; D2 z
#include "mex.h"
/ h9 n. H) F! d4 e; P7 }5 ?, k3 @! G' E' M* \5 i0 t% [6 C
void mexFunction(int nlhs, mxArray *plhs[],
! L! z" T3 Y K3 I
: |2 p) ^% t- `7 s% o* w# [ int nrhs, const mxArray *prhs[])1 f2 D$ i5 R( i- w! D! K8 Z
' |5 z7 I( q/ K/ q8 R% ~" l2 Q* C5 ?
{
/ P7 s; [3 d/ C+ @+ J; q
: p2 X. ]3 i) [, `int *i;
1 v2 [+ z) P, b" x/ J: l8 ~. {. A: G1 i' ?3 k) C9 F/ f& Z1 s- z
i=mxGetPr(prhs[0]);
+ ` C7 @7 Z) Y; X* M
( K( s3 e7 Y Q' z5 v0 o6 tif(i[0]==1)
; {( p- L! |$ D( t* C( ^6 H9 G8 K1 p$ N: B2 Q3 R0 a8 @
mexPrintf("hello,world!\n");
0 o+ m+ V, R6 ^; X- Q0 f7 Y$ P7 A% ~8 o2 B3 N9 ?
else) k4 C$ P% u- v0 U* r, L8 l
# @8 V' `6 ^8 Y- m1 z4 ^# p* w" X- c
mexPrintf("大家好!\n");5 J6 F, s4 N* o
3 N8 O# }* a0 Y' u! ^7 a& [" O
}% f+ e; l6 [+ p$ g$ E+ d/ [
! i5 `, [- e3 ~$ Y: U K5 g
; i+ x- q L# _$ v 这样,就通过mxGetPr函数从指向mxArray类型数据的prhs[0]获得了指向double类型的
1 Z9 m$ {# |% H. D: M+ @+ T% Z4 c0 c! j. Y9 i4 m
指针。( c7 e8 j S% w1 }
7 ~$ }. a1 H% H; F
. D& ?: i1 _- @4 b/ b 但是,还有个问题,如果输入的不是单个的数据,而是向量或矩阵,那该怎么处理呢, k, L5 ~1 f! @: ]) u' A
$ R) ]/ t# Y. C?通过mxGetPr只能得到指向这个矩阵的指针,如果我们不知道这个矩阵的确切大小,就
! Q& r5 Y6 n3 V `9 ?$ A( R" w; Q5 Y# V' [; R7 X% L. Q) I
没法对它进行计算。
4 A/ o5 S; Z B/ _) S+ ?1 p2 X+ ^* g2 r( ^. e4 r" N
. U0 d3 Z6 f$ U 为了解决这个问题,Matlab提供了两个函数mxGetM和mxGetN来获得传进来参数的行数
4 G- X( Z s! \7 T2 w: C6 g) ~9 t
和列数。下面例程的功能很简单,就是获得输入的矩阵,把它在屏幕上显示出来:
3 H; X: t" `9 x6 }- [. Y. F
! {+ L. G2 l. v, p( X//show.c 1.0
" q1 Z! F! C9 @- H2 a4 e7 S# J. M7 [8 W
2 P" O% q8 q" O; u+ g
#include "mex.h": f$ S! Z1 |6 }6 H2 `2 V
{" p; T% O& T/ S
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
9 d! w! u$ T- }) q( Y! b6 a# D) X' b0 E5 Q
( L0 [0 m0 X9 P4 G8 a7 G2 M{
' ^8 M9 A$ `% Q+ p: F
/ V% x8 N* E L2 R) idouble *data;
( F8 u! Z5 V; m. m
/ {/ n1 K1 G, P8 z. `int M,N;! t5 S; r; S9 j! V
- E* n# r, W: E9 a
int i,j;9 q1 H( n$ G1 j" Q
: ] r- T2 I! k" K
: ^) m' |1 u- Z4 b
% F3 ~/ q1 \! q$ gdata=mxGetPr(prhs[0]); //获得指向矩阵的指针
, _9 V4 ^( e4 x2 e5 v: z0 j
5 u8 d9 }6 P- X! R4 X- \M=mxGetM(prhs[0]); //获得矩阵的行数
4 x* Q6 w5 L6 ^: }# t" j
7 v& ?: _$ i) i0 @, x R- w$ WN=mxGetN(prhs[0]); //获得矩阵的列数' p0 b9 p( ]& s" w6 L7 k5 ]9 h2 @
8 a+ \: H9 x: l q, k# D" D# y+ f! y2 y V% \
for(i=0;i<M;i++)
4 j' e8 i& l: z8 t% M
( X4 `0 T8 o# G$ Y% j{
S4 Z/ q. s& E7 a
( e: `) x+ P0 ]; y$ Y for(j=0;j<N;j++)* X6 ]7 n# U1 R6 p C+ _( l9 E3 M
( c; b8 D9 X' C" o mexPrintf("%4.3f ",data[j*M+i]);
7 L: N1 r! A- I _! g2 Y. O5 ?6 U5 V+ K/ O, M
mexPrintf("\n");
: E* I+ }& R/ O7 v; {, r* c* Y* ~" `. I8 ^' E7 C. d7 ^5 u& ]
}
1 `& |6 a7 W1 Z# _
1 m$ C( A" b5 \}7 c2 q) i8 i1 j8 G
# I% l H7 q. Q [) o+ J
D* F$ X( A9 x4 e3 ? 编译完成后,用下面的命令测试一下:
, P( m2 C, a# ^1 {0 ^* F% s J( Y6 k7 ~ u4 J
9 J- K' T4 v F* \9 q; h5 v6 \: N a=1:10;
5 x8 y% `* z9 c: v; v# Y, Z" L, j7 T& ~1 ]! Y% \" N/ r
b=[a;a+1];. \/ s+ ^: U& z' I' a
* ?; D& B o5 A8 s
show(a)
9 Q+ F5 V9 M2 \+ p% i1 b, n
# ^5 B3 T1 W+ `4 L; p, W' j5 \ show(b)5 b% M$ V" @4 B7 U) F2 C2 S- Z. g
t) `9 v2 b. ]$ V
8 u8 Q0 `: Q* R0 @2 G% U5 C 需要注意的是,在Matlab里,矩阵第一行是从1开始的,而在C语言中,第一行的序数
2 h8 F! ]6 o. `. F: z( W( r; T
7 Y& F( y4 k% O: g为零,Matlab里的矩阵元素b(i,j)在传递到C中的一维数组大data后对应于data[j*M+i]! N- v0 a, T( {$ J* e# g1 @8 K
/ O: V& K5 u: I Q V" A: o; n。# W5 N- m- O7 B- z
. ?' S0 t& N9 j/ f1 P
输入数据是在函数调用之前已经在Matlab里申请了内存的,由于mex函数与Matlab共用同! n0 V4 K5 X4 F# }" F) A& l
一个地址空间,因而在prhs[]里传递指针就可以达到参数传递的目的。但是,输出参数
+ W( k/ M4 L. a. y- W: \, }% Y却需要在mex函数内申请到内存空间,才能将指针放在plhs[]中传递出去。由于返回指针; r, }. j/ O4 o5 `& ]9 t T
类型必须是mxArray,所以Matlab专门提供了一个函数:mxCreateDoubleMatrix来实现内
: R( R6 t- y, l( F* L& |存的申请,函数原型如下:, P8 H) T! r B& ]0 D1 [. I
mxArray *mxCreateDoubleMatrix(int m, int n, mxComplexity ComplexFlag)0 n4 R: p; h" H: ~# ^& E' L9 \
m:待申请矩阵的行数
6 @+ S V) E+ j* J' g/ Pn:待申请矩阵的列数
! o! C1 h) D3 e. N9 ]$ v: [/ Z为矩阵申请内存后,得到的是mxArray类型的指针,就可以放在plhs[]里传递回去了。但+ r; I/ F: z3 s+ i
是对这个新矩阵的处理,却要在函数内完成,这时就需要用到前面介绍的mxGetPr。使用! ~ }! T( W% S" l
mxGetPr获得指向这个矩阵中数据区的指针(double类型)后,就可以对这个矩阵进行各6 f8 e3 E! E* g! V" T& V
种操作和运算了。下面的程序是在上面的show.c的基础上稍作改变得到的,功能是将输8 B- W, Z& q. ]
( Y* h, |6 e- U0 y" H0 V" F//reverse.c 1.0
& X' w7 a p4 `9 P- ~2 I8 J" I& A r& S# p$ q
- W' }# p5 [% Y M3 L* l#include "mex.h"
% B) \ {7 `3 w% m- H; S
8 _& s3 M( g6 B* ] ~8 K! [void mexFunction(int nlhs, mxArray *plhs[],
5 j& B" S$ K' `
" b3 a2 Q) [, t+ m5 H int nrhs, const mxArray *prhs[])
/ J9 E3 \: ]/ S/ {. y T$ l; e6 P: V. X0 k
{
( A3 S. F8 Q* b$ `/ w! Q# v8 c# }7 Q
, b4 E8 K N E" Ldouble *inData;" q1 j0 f* W) `, ~' A
# R3 f9 Y3 A2 Y( V# S
double *outData;# p$ ?6 a* J$ ?
1 I3 I! |' ^ |: [0 b6 \: pint M,N;; t. b; o0 `+ M1 g9 E( Z7 w( v
9 z0 w4 E* p$ x+ jint i,j;
* y4 ~3 ]/ o+ m: @; }- p! s ?# m( t. W$ l+ H4 @6 [- @
/ }1 a( X* C0 E
8 b; G( U# K5 i1 a1 D! n, s
inData=mxGetPr(prhs[0]);) N6 G8 B' h) X
4 W7 r# n- S4 J7 o
M=mxGetM(prhs[0]);+ B# p# I+ O2 _
9 l+ p! f2 J. b+ C/ q
N=mxGetN(prhs[0]);; R& L; @7 d; l3 ^* X
+ b% P! H+ J6 k4 M) g' M3 m
s. ?9 K; ^' `* Z9 K
plhs[0]=mxCreateDoubleMatrix(M,N,mxREAL);" l3 q- I& W# ~) D4 ^! i
/ L/ U! Y8 z1 a% Y' {6 U3 c: W
outData=mxGetPr(plhs[0]);
( x8 Z6 W' e8 n; _" M0 {' V ~8 g* F( ~! \8 Z) {2 o, g, l9 F% O% v4 D$ Q/ d
/ G* p6 Y; F5 \ a/ D$ w4 h
for(i=0;i<M;i++)+ r) ~2 ^7 R, G+ L& I3 W& h6 A1 M
' |$ l. D* j9 H$ ]4 m for(j=0;j<N;j++)5 C }7 f J \) r3 D# ?+ x
% ?% h) Z8 S3 C, e6 L! h* D outData[j*M+i]=inData[(N-1-j)*M+i];
0 a: y1 i7 ]2 r. e9 |/ ^
1 |! c5 x6 t* Z/ B! ^) u0 L}& [8 y' |$ L& b0 {( X, v: \
% [5 Y; {2 c& v0 h
* P/ z8 O- [ ~& x' E8 p9 |$ k( M& j
当然,Matlab里使用到的并不是只有double类型这一种矩阵,还有字符串类型、稀疏矩
8 N ^0 c& k- J+ E- [- R
# a8 E3 v7 P6 D% i阵、结构类型矩阵等等,并提供了相应的处理函数。本文用到编制mex程序中最经常遇到; q; c7 d$ K$ N
4 Y% y% V/ f( x G6 D7 b ]
的一些函数,其余的详细情况清参考Apiref.pdf。
! j9 N3 \$ L, h$ I' }0 d- j/ F通过前面两部分的介绍,大家对参数的输入和输出方法应该有了基本的了解。具备了这
4 w0 @! [' R4 [些知识,就能够满足一般的编程需要了。但这些程序还有些小的缺陷,以前面介绍的re) g j. O( b1 M% p
由于前面的例程中没有对输入、输出参数的数目及类型进行检查,导致程序的容错性很" L' w5 `2 A1 O! R0 t) @
#include "mex.h"; ?, W+ g# ^! I# N, q* l
void mexFunction(int nlhs, mxArray *plhs[],
# M' `& }9 s* ?. `# o1 h8 B; h int nrhs, const mxArray *prhs[])2 w( X( j% p. V
{
$ f+ p/ h7 e2 o, u# H2 Fdouble *inData;1 F" S: D' A5 I2 N
double *outData;1 `" h D9 c0 C
int M,N;
) ^; o8 \+ J* w) m//异常处理. O* G3 }4 q# j! |3 j( W6 U
if(nrhs!=1)/ r$ Q9 p( t: z# U9 B: u1 ~
7 @0 }! t3 [3 x3 g- s2 k L mexErrMsgTxt("USAGE: b=reverse(a)\n");4 `3 J: }7 v* ~# c4 \9 J5 c" h
$ q! ?' S( \+ S; V/ ]- F& hif(!mxIsDouble(prhs[0]))' A! {) R! v- Q
* _* y+ L: v7 O1 ]
mexErrMsgTxt("the Input Matrix must be double!\n");
- i( w* @. G# g7 z3 O- n7 f1 E. b' T) E3 k) ^
7 m& U( ], [! c7 rinData=mxGetPr(prhs[0]);0 M" b7 k d$ M* x
* ?* h. _' `- A) Q
M=mxGetM(prhs[0]);. L) `! b5 ^; Q7 [: {2 K1 C- J
3 R; }) Z$ i! H# g& s9 R
N=mxGetN(prhs[0]);! J# M9 ~- t1 M* `2 [1 |. `# L
) ^9 a T: a& h# }
6 C9 H5 d, \4 u/ T( Z' k. O/ Wplhs[0]=mxCreateDoubleMatrix(M,N,mxREAL);
+ V8 l6 k2 b8 t, x- b
+ \$ d; D" e3 d4 xoutData=mxGetPr(plhs[0]);
0 s2 B' ~" v5 K& l5 ^
& K* \# p, I% i. H& z7 z) Q6 A' q
for(i=0;i<M;i++)
: l3 r% v7 t+ x; @% o+ ^( P c$ O, [) p8 h# A( t+ C- t, B7 ~
for(j=0;j<N;j++)8 l( @+ c- m) }$ T$ q9 z$ a
5 X" c3 D8 k! A8 N% u' W9 l) o
outData[j*M+i]=inData[(N-1-j)*M+i];& x- m5 ?# h* q) _& h( m1 ~
! M+ M* _% x# i+ _& b0 Z}% I5 I. {" E4 R; ^3 f
, v5 L) g7 b2 ]; f
# ~9 g% t, r: [2 O7 a u: Y' Q在上面的异常处理中,使用了两个新的函数:mexErrMsgTxt和mxIsDouble。MexErrMsgT" w0 u8 {+ e3 ]0 b- B: K
: V+ Q0 `& u4 Z+ [. e3 w
xt在给出出错提示的同时退出当前程序的运行。MxIsDouble则用于判断mxArray中的数据
! M" ?5 t L6 |- m" U
2 c: m$ H/ r$ N) {: a' S8 ~是否double类型。当然Matlab还提供了许多用于判断其他数据类型的函数,这里不加详
, Z; Y% o( ^: c# b" s% c
$ J8 u/ U Y# `5 y7 {述。2 ~5 D6 t( @. m: ^2 X) k G1 {
- \0 P0 i0 E/ r
2 F, k0 F1 f8 M3 o" o; [需要说明的是,Matlab提供的API中,函数前缀有mex-和mx-两种。带mx-前缀的大多是对8 E; i @4 i6 m6 ~+ Y
8 b. q; Y* k; D( D: K- s
mxArray数据进行操作的函数,如mxIsDouble,mxCreateDoubleMatrix等等。而带mx前缀
( @* I/ p! T3 q. n( W0 b2 ~
/ e) Y6 d8 I, R" b的则大多是与Matlab环境进行交互的函数,如mexPrintf,mxErrMsgTxt等等。了解了这
; f8 n' _' D2 r2 o! J$ O% \ \) w) k. p
一点,对在Apiref.pdf中查找所需的函数很有帮助。. v! Y" z4 s, |
; m* q! [5 D: v6 t4 q
1 G+ A. u+ `# n: K* H. M至此为止,使用C编写mex函数的基本过程已经介绍完了。下面会在介绍几个非常有用的( Q' T; S: D$ K; k8 @( e9 Z7 W0 d) {
) `* a* H8 c# V% D4 `, b; o函数调用。如果有足够的时间,也许还会有一个更复杂一些的例程。
, u. m o( _# t8 B' N
) V; p! t# t# o, _% W我们之所以使用Matlab,很重要的考虑是Matlab提供了相当丰富的矩阵运算函数和各
4 |9 G3 i0 z7 t+ z; k8 X种toolbox。在编制mex函数时,有时我们也会遇到一些操作,在Matlab下,只需要一个
0 j) Z: ? ~* N/ m$ _5 u$ j9 g为了在mex函数里调用Matlab命令,我们就需要用到一个函数mexCallMATLAB,原型如下:: {6 h, N6 h' a( y
int mexCallMATLAB(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[],
% J/ Z4 W# p. s/ k$ x8 ~ const char *command_name);
! S; [) M4 \5 s; ?0 C有了前面的基础,使用这个函数就显得十分容易了。下面给出一个例程,功能是将输入
3 e$ R( T; A: r( {' m' \2 u#include "mex.h"
+ M( ?, W1 @1 g% P4 Q6 o, Gvoid mexFunction(int nlhs, mxArray *plhs[],
7 g$ y8 H4 M! l* z) ^ int nrhs, const mxArray *prhs[])' f, ~' d; }' W$ Y; T
{
* ?- d' I' z: C& r
* i* L& K) T% q% fdouble *inData;' I5 X4 ^. a6 k
n0 A2 C' E/ ~' zmxArray *IN[1];3 Q" x8 M6 o9 I6 H$ Q5 o
' @% r* k) x7 q7 c, B# ]5 r
mxArray *OUT[1];6 Z* z' X+ ~- \
0 F5 U0 d* p$ m/ n Odouble *outData;
. Q0 t3 b$ ?! h, c
# R# c1 s9 T. C" ` I. b7 P; aint M,N;
# X( T e! \: R8 ^8 E5 E9 n! d
int i,j; A* @) p7 _! n, D
8 M) L, @/ q v* M3 i$ h
0 P+ v) t1 |# m2 \ G3 z/ e: k; L//异常处理1 k; b; w0 N8 p6 n0 a) u
8 ~; H2 \, B4 c8 D8 V
if(nrhs!=1)
) O% X3 U& G% h% J! R; w
% Z& C) L( g, l% b& T mexErrMsgTxt("USAGE: b=rot(a)\n");
1 E# T; R' s. G4 G- p$ \' k( L1 p3 L. m7 j+ j0 |
if(!mxIsDouble(prhs[0]))4 _2 s% \! ~; A: ?
* P# N( w7 a$ j* E! ~& [
mexErrMsgTxt("the Input Matrix must be double!\n");3 H9 [$ i. o, h0 \" c5 e6 c
% k0 Z$ o* ]9 x
: v' G' R6 x* z& P' K( h//计算转置
4 ?, u5 U0 R$ H6 A1 G6 L* J) f. N4 Y
; b6 c# V& R7 K2 J) s6 \$ _0 fif(mexCallMATLAB(1,OUT,1,prhs,"'"))
: W% N8 x% ~5 W+ [7 D/ s% [) e1 W
5 |- E+ @/ `1 X7 {, c) b mexErrMsgTxt("Error when compute!\n");
$ c6 d0 @% N; h Y6 W0 U/ ~$ P7 D5 L& _+ y
c8 F% N/ z6 ?7 r4 b H
//根据输入参数数目决定是否显示
) ~ J; g; V. E7 i) P3 L1 y3 V4 T Y0 c$ }
if(nlhs==0)
! D" R6 ^* F- }/ Q" r2 G6 m0 Z
$ ^: M* z9 U! `; [3 W mexCallMATLAB(0,IN,1,OUT,"disp");
2 u6 Q. t ~4 ]6 b0 ^& F$ W5 u5 _- }$ C @! \+ `) ?
else
- w$ G% Q, `9 _7 w4 ^* _
3 A0 I, ^# D1 ]# \0 S plhs[0]=OUT[0];7 l+ m2 l' j# T$ g% T( O7 t: z. i3 [) m
* A* S' s% S7 |} |
|