|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
3 |7 n7 P% e, d, T8 T+ g- ~ Matlab 拥有丰富的功能,编程简单。不过,有些情况下,Matlab程序的执行速度比较慢。C/C++编译执行的程序速度比较快,编程难度上比Matlab要高一些。因此存在一种方案,就是使用Matlab实现我们的实验程序,用C/C++来实现Matlab程序中比较耗时的部分,从Matlab程序中调用C/C++的程序以实现加速。
4 K' g+ A; C2 T. d% c0 c3 _1 q6 \7 W
- B, ^; T8 W2 C+ p- l6 R" D+ V' m 本文主要讲解如何在Matlab中调用C/C++的程序,以及如何编写可供Matlab程序调用的C/C++程序。
- Z+ V6 s0 i2 l7 K" Q' d
/ M0 D( ^% N- G8 ^# a" U. t) _" Y" p 本文主要分以下几部分:: f1 D8 s% d! q" ~
2 y% ^( G- d1 M Hello Matlab,用一个简单的例子来说明如何在Matlab中调用C/C++的程序,以及可供Matlab调用的C/C++程序应该注意哪些基本事项。0 b$ E& ^# v5 U, h! y# y D$ v
$ H$ c; U% ` t Matlab调用C/C++程序传递参数。讨论在C/C++中是如何使用Matlab传来的参数的。
" g q( \; L8 r" @# _
( o, |& J+ l1 P Matlab与C/C++混合编程的方法论。给出在一般情况下使用Matlab与C/C++混合编程的方法步骤,让大家有一个较为清晰的应用此技术的思路。
( u) f# B/ }$ ?: o x6 `
" X( }8 g3 z- k 关于数据存储的说明。说明数据在Matlab中的存储方式。
]/ X! t5 ]- d& l& V; S" k7 I
" L4 ?& R1 [- c) Z/ U. n' B 注意:本文认为读者会使用Matlab,掌握C/C++语言,并且有一台计算机。计算机上安装有Windows的操作系统,操作系统上装有Matlab以及Visual Studio(比如VS2008,VS2010等)。或者计算机上安装有Linux的操作系统,系统上装有Matlab,GCC。
) x; U: j8 k# g- g D( J+ G9 ?( Z
% [. r9 U3 x3 Y4 k0 u8 [% H2 ?( M; r$ u
- Y+ f' ^5 H2 Khello Matlab
- |. T2 M! K+ D5 b8 Q% A- K 我们一步步完成一个叫“Hello Matlab”的程序。
! a1 a' r+ O, z- a% H U0 c$ E$ [3 D/ M4 o3 v
第一步:在你的计算机D盘下,创建一个目录命名为HiMat。在D:\HiMat目录下创建一个文本文件,命名为“abhimat.cpp”。将Code 1中的代码拷贝到“abhimat.cpp”文件中,保存。(注意,这里建立目录以及命名等行为不是规定的,只是为了讲解方便)。6 ^4 k+ L: j& t6 c2 V5 m- D
% `/ o5 N$ C0 k4 c2 L! U" A$ h- #include "mex.h"
- void mexFunction (int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
- {
- mexPrintf("hello matlab in C/CPP.\n");
- }8 \: e4 ~" L, w! ^
4 u! E1 w4 r7 w2 v% ^" w
7 U- G. M9 f: J. ^Code 1, abhimat.cpp" I! r! U+ r5 d' ]0 J' p; F
“abhimat.cpp”就是将要在Matlab中被调用的C/C++代码。/ D0 a4 C% `: s9 a. p& y$ M
6 N5 E( c7 q2 `$ X
第二步:在Matlab中编译“abhimat.cpp”。启动Matlab,进入D:\HiMat目录,在Matlab命令窗口中执行code 2中的命令,根据提示完成C/C++编译环境的配置。注意:如果你有多个编译器,建议选择最新的。- p: D1 X' G0 Z
m" P( g1 _- c/ ?$ W `% n8 U* U' N: z
- mex -setup
6 q h5 F2 T7 }) ?- u1 g+ `' ]. b * ]0 ^, U+ L6 M) f, _: k
7 c7 I [" I6 M7 [0 ACode 2, 设置Matlab的C/C++编译环境
# ^$ L- S/ [2 c" H( k, T! A: V, v Y4 V- n" y+ x
完成配置后,在Matlab中执行Code 3的命令来编译abhimat.cpp。" C( o" a: ^" v7 g2 N. m7 O
# l( Q& c/ Y8 r/ n. Q) _
0 G t) P% f3 q
- mex abhimat.cpp
) z) d6 t5 H- Z' _- n2 X! L) b! }* g& R
( e5 p( |1 a1 j9 P% v: d6 x) d
( Z4 d. h3 G: e n& }) U. MCode 3, 编译abhimat.cpp* `# H2 m5 @: d6 D/ P) u, r; ?2 N
1 `6 V9 Y6 a+ O! ~; A& @, ?
第三步:执行编译后的C/C++程序。在Matlab命令窗口输入“abhimat”或者”abhimat()”,都可以调用编译后的程序,推荐使用后者。3 `8 Q o F1 q: |/ K5 k
1 o. a7 K1 @% H' o* P
细心的读者已经注意到了:
! \8 r8 ^3 e6 G1 i% A- A
4 d0 P0 D' P) [- I$ K- 在Matlab中调用的C/C++函数名就是编译后以mex*(这里,*表示任意多个字符,例如mexw64)为后缀名的文件名。
- Matlab执行abhimat()命令后,实际执行的是mexFunction函数中的程序。
+ G" M/ ^( m9 P) k* U1 Q
% f! a" l5 r, n8 ~7 I, N1 P% c
9 t4 P, J0 j# D1 ~, GMatlab调用C/C++程序传递参数* c3 a9 t2 W8 F/ B; D8 [
/ T; p4 N! ^) u, u2 P K
此节我们讨论下,在供Matlab调用的C/C++程序中,我们是如何知道Matlab调用的参数类型、个数的。
$ j6 ?7 @& g2 {6 a! X' r- u* u: G+ v$ n
给出Matlab中调用C/C++程序的一个实例,如code 4所示。
+ L: z& Q {2 L- ]' X7 F& S' w
. j+ z& x; T- e+ B2 H# \0 ?5 k
1 ]( E1 K9 I8 l9 l Q! `- c = [1 2;3 4;5 6];
- d = [1 1;1 1;1 1];
- [a, b] = abfunc(c, d);
7 R0 P5 |5 x: w8 `0 k3 H' a 2 K3 j6 X+ a' q- F- q" U
# x6 ]! y% K$ J. G- o$ Z- e
Code 4, Matlab调用C/C++程序实例3 B0 S* ?# |6 Z6 \$ Y. a0 V
7 u' d" [4 S/ e: Y
下面的工作是如何在当前目录下一个命名为abfunc.cpp的文件中实现mexFunction函数。在这个函数中如何获得Matlab命令中的c、d两个变量的值,如何返回a、b两个变量呢。7 {* E. r0 ]# T6 K
) b7 x7 L1 l6 D
注意mexFunction函数中的四个参数,一一作出说明:) H/ t. T# ~% E- o2 R; \
; Y' A! r3 U; s3 u( S! O
nlhs:mexFunction的第一个参数,它指示Matlab的调用命令中等号左侧有几个变量。例如,code 4中的调用,nlhs的值为2,因为它的等号左侧有两个变量,他们是a和b。7 m4 q) O$ s6 b u% q/ u* ^8 M* j
9 ]. Z# s4 ~7 O) s4 B Z( D3 f
plhs: mexFunction的第二个参数,它指示Matlab的调用命令中等号左侧变量的指针。例如,code 4中的调用,plhs[0]表示的是a,plhs[1]表示的是b。
, V) h# n; l6 Y# d: p/ g g' @0 G
: h$ V! d( v* X8 b nrhs:mexFunction的第三个参数,它指示Matlab的调用命令中等号右侧的变量个数。例如,code 4中的调用,nrhs的值为2,因为它的等号右侧有两个变量,他们是c和d。
+ L" Z$ m- Z! `, l, Z
% `8 ^( C8 E7 q% n; e+ w4 l2 r prhs:mexFunction的第四个参数,它指示Matlab调用命令中等号右侧的变量指针。例如,code 4中的调用,prhs[0]表示的是c,prhs[1]表示的是d。
( t1 l& b2 s& c; ~) o- R1 W% ^9 R* P9 y8 E7 H% g" L
mxArrary是一个不可见的数据类型,是Matlab定义的,大家只需要知道mxArrary的指针与Matlab中的变量一一对应就可以了。
) Q: _- k- C. i5 y( M h* I4 M9 ]5 J: u1 T- K5 J
下面实现abfunc.cpp,功能是a=c+d; b = c-d;具体代码如code 5所示。 f9 j! q: C! B# M) u* B
9 t; @* M+ I9 N6 x- @% o% [( Y- #include "mex.h"
- void mexFunction (int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
- {
- double *p_c, *p_d;
- double *p_a, *p_b;
- int c_rows, c_cols;
- int d_rows, d_cols;
- int numEl;
- int n;
- mxAssert(nlhs==2 && nrhs==2, "Error: number of variables");
- c_rows = mxGetM(prhs[0]);// get rows of c
- c_cols = mxGetN(prhs[0]);// get cols of c
- d_rows = mxGetM(prhs[1]);// get rows of d
- d_cols = mxGetN(prhs[1]);// get cols of d
- mxAssert(c_rows==d_rows && c_cols==d_cols, "Error: cols and rows");
- // create output buffer
- plhs[0] = mxCreateDoubleMatrix(c_rows, c_cols, mxREAL);
- plhs[1] = mxCreateDoubleMatrix(c_rows, c_cols, mxREAL);
- // get buffer pointers
- p_a = (double*)mxGetData(plhs[0]);
- p_b = (double*)mxGetData(plhs[1]);
- p_c = (double*)mxGetData(prhs[0]);
- p_d = (double*)mxGetData(prhs[1]);
- // compute a = c + d; b = c - d;
- numEl = c_rows*c_cols;
- for (n = 0; n < numEl; n++)
- {
- p_a[n] = p_c[n] + p_d[n];
- p_b[n] = p_c[n] - p_d[n];
- }
- }
7 r4 t1 |4 M0 p0 H1 h+ W* T4 B
Q5 }9 J( o* c9 p5 r: ^8 ECode 5, abfunc.cpp的实现! f8 Z5 K/ u! [6 `
r1 r4 f% K9 i1 w- ~! M( R1 | 说明一下code 5中用到的函数。这些函数大都以mx开头。mxAssert是断言,类似于C\C++中的assert。mxGetM获得Matlab传来的变量的行数,mxGetN获得Matlab传来的变量的列数。mxCreateDoubleMatrix创建一个2维的Matlab变量,形参分别用于指定变量的行数、列数、元素类型(mxREAL表示实数,mxCOMPLEX表示复数)。mxGetData用于获得内存中数据块的首地址。
2 Z. W# r; a% T {+ L7 w- Z2 |8 i7 O1 K
编译并测试Code 5中的代码,参见Code 6。) ?* e5 e F/ r- B
3 b% X \- C" B
- mex abfunc.cpp
- c = [1 2;3 4;5 6];
- d = [1 1;1 1;1 1];
- [a, b] = abfunc(c, d);
8 E/ R, U- p1 }" K / @6 V; j0 c) O4 ^
; Z3 K0 C4 z' [. z% \
Code 6, Code5的测试代码2 ~* V' S" T+ a" y, s% K
/ O( g- {3 j) t7 M% p- w0 a% u9 S Code 6的输出结果如下:
1 h. d& h* T; X& ? F1 i
8 N# ]% a! q% ]- a =
- 2 3
- 4 5
- 6 7
- b =
- 0 1
- 2 3
- 4 50 k8 E/ X. d2 j
5 Z6 L R; j0 O. ]
- u4 x# L0 c5 ?+ O+ y8 |6 K关于数据存储的说明
z' J7 L1 k) |" h+ {: S) o! r' P- Y/ {; X; [" j% E" t
Matlab中的数据是按列存储的。例如,a=[1,2;3,4;5,6],a的数据在内存中的存储顺序是:1、3、5、2、4、6。在C\C++中使用Matlab传来的变量时,一定要注意数据的存储顺序。
$ Q% s; y& x/ V9 @& w! N
8 o2 ` P" P: t% Y
- T3 V% @; j6 U- Z' N. H+ ZMatlab与C/C++混合编程的方法论
; X' J1 x* }# p8 U; _$ G4 X" j5 k1 V( ?3 `, L7 t" o
鉴于@编程小手 的建议,添加一个关于使用此方法的方法论流程图。希望它能让各位明白在什么情况下可是使用这种混合编程的技术、如何一步步实现。参见图1的流程图:6 Q; e3 M, A& V, ?5 t
. Y- W# W# m* ~/ ]# J1 | E
$ y/ C$ T+ H% R$ l
7 X; u ?% r, ?1 U% K7 i
图 1、Matlab与C/C++混编方法论流程图8 G- _) o! Z" Z& O: l; d9 k
|
|