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