EDA365电子论坛网
标题: matlab与c语言混合编程 [打印本页]
作者: mutougeda 时间: 2020-12-10 13:41
标题: matlab与c语言混合编程
前言:众所周知对于循环这种运算,matlab的运算速度是不快的
想起来个冷笑话,黑客帝国里的主角呢奥之所以能快过子弹,因为Matrix是matlab写成的hhhh
因此将循环部分用C语言写,然后编译成matlab可以调用的mex文件,无疑可以加快循环运算速度,从而加快整个代码速度
之前因为合并数据需要不会数据库,强行在matlab里利用类似excel的vlookup功能,无奈太慢,只能想办法最后知道了这种方法,最近偶然在桥哥的知识星球里又提到了,也顺便复习和记录一下。
ps:今天在闲鱼上买了小车车,高兴!
1.环境配置我的是matlab2019a,win10-64bit,c语言编译器我选的是TDM-GCC(gcc/g++),安装起来很简单,推荐matlab2015及以后的选择这种,详细安装过程可以见文末链接1中的For Matlab 2015部分
* h8 o' K) A/ ^2.如何编写可以被编译成matlab可执行文件的c语言代码我是在matlab中文论坛(地址见reference第2条)里找到如何编写的,不过他写的有点乱,我来消化后写一下自己的理解
mex接口函数跟一般的C语言文件主要是两点区别,
第一是必须引入头文件mex.h
#include "mex.h"第二是多了一个叫mexFunction的函数
void mexFunction(int nlhs,mxArray *plhs[], int nrhs,const mxArray *prhs[])举个栗子:
- % H0 n' t0 a9 h4 V% Y! p% O
2 w9 z0 T: ~. @4 z; S#include "mex.h" // 使用MEX文件必须包含的头文件; Y! w+ \9 o! Y' M
: w. j' m+ \$ z, d. C7 X
( [' ? \1 u! |. k* Q% }5 P! T
% V( Q& W) G; M, y// 执行具体工作的C函数
3 U; X# j l; C$ W* [
0 P" J: n J1 g6 x- k$ v: A
. m5 J2 I& ^+ E# }' J3 R% s X' K& i5 H+ x% Q2 V( N
double add(double x, double y) T v6 `5 [' B/ D3 g
8 o1 M# P! c% Y5 [- ( v. g3 s: N5 Q/ d5 z5 B
( O3 n: c% R3 R. T# l{
4 h% z5 n5 r8 r* w+ Q! X
1 n+ t. _0 ~7 P+ P! D3 ^/ R! a* p5 o
; D8 q, o& j+ K- V8 I8 ^* t6 x
& D4 p9 r; s4 `8 E' r' R% L) o return x + y;) G0 r/ S" [1 s8 N( Q6 P, o
) H# Q* X* h, h4 U& s- " o+ t! Y$ N" E' f4 r, w- N5 k- Z1 V8 y
g" o( o2 o: T! m# F}
4 n. V8 f! j! x* o1 n4 {% N0 g: A4 M e- Y
- % T4 v% z* V+ j) q5 }, a" I
! F+ r0 d( }* Y; q& \$ s; ~
// MEX文件接口函数
% A& a' J% ?. K! R- i1 I t( B( ~2 O5 |$ X2 \" l2 r) a: o
. Y6 T. p8 M8 }2 l' f( T* d" a4 C( R" i& c) S+ x
void mexFunction(int nlhs,mxArray *plhs[], int nrhs,const mxArray *prhs[])
: _/ C4 f# ^5 s8 T: M
; Z' w) J. ~+ l5 |; }$ |
% _6 s/ u% {% J. N( w7 X
# O4 ]' _3 W: d3 c{
7 ]( t# X+ x* E1 B) i' [- p. @. B8 R
- + P: h; |9 ^* Q' G
P# a3 t `, L& {9 H+ X double *z;
3 f- S7 U) g; z5 l9 D, X. T# R% e: f- Q D. Y" @
3 G# F1 G; l/ }' M
# Y; T: v0 f/ ]) Y double x, y;- c6 m1 A4 z+ ?* ?6 ~/ P$ `$ r
5 t; |+ j' O$ P) [9 S( o7 b
3 W+ w- K. h8 Y2 h
' |9 {) ?1 L. i plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL);
( u$ f( ^- T) V* ]. U. k( n& X! T3 X8 _+ H8 |6 X! C
- 4 a) M' J! `) M
- h9 x/ t0 R: [3 x7 f
z = mxGetPr(plhs[0]);
5 X" ?2 o& n7 Q( z3 [! g$ E0 h0 v- V4 I
- " s4 ^0 k; q, g& A1 n
' N1 X, S6 [/ Z# A& h; w4 z x = *(mxGetPr(prhs[0]));
- a9 a$ N% K8 f- U, x; q: O n8 v7 A$ w$ ~% g$ g# V% D
- - f ^8 b) a% c' H; a
- P W+ U( u; }+ s: K* L y = *(mxGetPr(prhs[1])); S$ p$ ]1 i+ q5 m2 `
' A1 h5 r2 W; Y9 U - % @& Z/ G$ _4 T2 z( N
3 f$ F2 [) K% u0 o9 k *z = add(x, y);: t5 s) z1 `, l( Q' B, D1 z' C
. z3 r5 l& Q2 ] f$ g( D+ X5 t - ; x, o" _* `" D" q* f
8 T; n8 S ~- M& R a# s% u" {, d}
8 v( C% x, x1 z0 z/ ^' \: c6 [" b; v i
9 q+ Y+ Y0 v; N$ ^" P
也可以写成:
- , V; R; L1 M u% f$ e, P' d
4 R" k0 N% w2 [#include "mex.h" // 使用MEX文件必须包含的头文件
# G. v- n7 `1 u7 [9 w6 e4 \4 v
- $ y) c$ z: e3 B; \" x
; [% G% | R/ V% U7 J. H: V
// MEX文件接口函数
9 A) a v/ o8 i2 y# I/ v8 Y
, \- y7 Y x) q, g I4 c5 N
1 X* ?7 S% Q! X# R7 e0 O) `& i. W6 ^4 b
void mexFunction(int nlhs,mxArray *plhs[], int nrhs,const mxArray *prhs[])9 E! m z/ K4 P/ e3 y2 R6 x
% O* F7 V4 _0 N
- , A f0 R: Q2 W# a/ E
6 G9 l+ n7 m. ]- e$ v
{& \9 V* Z3 A0 d( A; U* p
2 {2 D S5 O4 u5 k: y. t. t( L
- 1 e. @( m" V2 P5 K7 B+ o u
+ q% H; \2 H' @: N5 [# j double *z;
3 S; g% K$ u' Z( ?+ B$ w1 ~4 s) O7 a/ T6 b0 O
1 V1 S/ T7 ]: s' \- q* R3 p1 x/ f" F
double x, y;* E8 N% K1 {- h! m6 I
+ w/ H" e; R8 p- / o$ n3 h: E+ [8 f+ U+ x+ O! }9 {: }
! X7 V2 ?: ^ ?/ x0 @3 u
plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL);3 v2 ^# Q0 ~$ A7 E" m, U6 K
6 Q" h' w- \& d7 t: T
- % S$ w% C6 X; W: y+ `
8 N) p2 \, l, `# o, x% q
z = mxGetPr(plhs[0]);9 L- `; T1 Y( H, _
- e8 K2 j: R6 h2 N# ?9 H, W$ b
6 B& b: P A7 x9 a7 T) Y) K
4 P: B8 X% W5 F, d$ ^7 U x = *(mxGetPr(prhs[0]));0 i; e* d0 d: L2 X4 d! x l6 l8 i
6 X% ]& d7 o+ ~0 {2 J2 x7 ]& H- z
5 z J$ o5 k6 q5 G& [3 g9 |0 J' t, Q4 q1 V% O
y = *(mxGetPr(prhs[1]));
& H- a4 P. P% ^" y9 P7 B3 y. m) a6 \ s a4 @/ R7 k
- , Z2 T4 g0 S( C9 d6 n
) a8 [6 A$ w0 v5 H8 G8 T8 v4 K( L *z=x+y;* v7 c3 Q: Z5 v% P
; U4 j0 Q! ~- l; b" {" z - 0 E$ h7 |: l, D" t6 f- f9 x7 P" _" N
" c2 } ~$ ~6 k$ W
}$ J, S6 H N: z0 }) \
# R4 K- h9 J l( y* s2 U/ f
5 ~1 X" s2 T F0 B* ]& y
也就是说执行具体功能可以通过编写一个独立的c语言函数在接口函数里调用,也可以直接写在mexFunction接口函数里
我个人推荐将具体功能独立出来,这样一来:
c语言函数负责执行具体功能
mexFunction接口函数负责数据的输入输出(将matlab数据输入c语言环境,运算后再输出回matlab)形式组织
再调用c语言函数
分工明确。
于是关键问题就是如何编写mexFunction接口函数了
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])下面解释一下mexFunction各个参数的含义(这里看到是void,即无返回值,因为传值是通过指针数组plhs[]传出的)
参数
意义
英文全称
类型
( [4 i5 n, g, q# D% \& snlhs左边输出参数的数目number of left-hand side整型(int)
0 S' \( x; U9 I" m) M: O( Oplhs指向输出参数的指针pointer of left-hand side指针数组
/ h( D5 X' [# o3 w$ \7 qnrhs右边输入参数的数目number of right-hand side整型(int)
& U6 v3 P0 r. n' r1 @prhs指向输入参数的指针pointer of right-hand side指针数组
$ X3 c4 j! ]8 b9 |% R: Q第一个参数nlhs是输出参数的数目,第二个参数plhs是指向输出参数的指针
第三个参数nrhs是输入参数的数目,第四个参数prhs是指向输入参数的指针
其中plhs和prhs类型都是指向mxArray类型数据的指针,prhs这里还加了个const,这里的const跟之前c语言中是一样的,代表不改变,因为prhs是指向输入参数的指针,mxArray这个数据类型是在头文件mex.h中定义的,in fact ,在matlab中大多数数据都是以这种类型存在。
还是拿之前的栗子来解释:
- ) `' X/ y b/ u- a2 R
2 K6 E$ D5 B; m; K3 w. V! n, f- i B#include "mex.h" // 使用MEX文件必须包含的头文件
$ b* g# y- r+ j. b+ i# h- k; f6 q" d1 O% G, D u
- ' F/ r: ^% Z( y" u; x4 j6 ]: h! W5 }
6 G* g/ \* W+ d7 \2 D+ D// MEX文件接口函数! Z0 F1 f s$ ^! r
4 [, v- U' ? Y3 q9 F. V - 5 R: z" z9 |7 p
) q, v' Q9 J0 X: _4 E4 Qvoid mexFunction(int nlhs,mxArray *plhs[], int nrhs,const mxArray *prhs[])
3 N" p5 e9 h3 Z$ l
! K, `: k4 a8 `6 y. R
5 Q4 d. U, f( @, Y# w9 T6 N- m% g [- |3 v4 E# X" B
{) ^' l9 Z2 V9 V" ^- b
* y+ I9 p5 y) {* P& K) ]
- 4 l6 {! K+ r9 N' ^0 y
3 r! I$ l0 u4 y, c" o double *z;: G5 C4 Z% S# ^( ]
8 D l3 W. y2 a3 b
% L+ E7 ^# |" A4 G6 l3 r* l/ W
8 O/ G& w6 r6 e( V$ |! F double x, y;' I, l) n" F# Q5 {8 i" J
2 _0 ~- V6 r7 M8 @" U" [
, H: a+ G- D# ? I7 H& @0 w$ V( D/ x/ ]9 c) [5 J: i( `
plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL);" v1 B3 @4 K1 i. O( X# y0 X% J
2 _. r: A5 W) @- 5 c7 O& N) v0 f. U8 [9 I. y
[2 A& p1 O: D# j* o& Q
z = mxGetPr(plhs[0]);) x) d I( s0 I. t- R7 S# r
9 P4 j" ]! ~' L$ W. y
- ( A, g* `3 c& |' g* Q1 N
( g- T+ t) t2 O/ x- i& F x = *(mxGetPr(prhs[0]));( P( ^1 V' }. T9 f* `
- E* Z5 R/ a' v
- 3 y! y& X1 l0 ?" F/ g5 b: j
3 _( Y3 W8 i m y = *(mxGetPr(prhs[1]));
0 O7 s4 G* v3 C' r! s
$ W, s( ^) k- U P - ! V/ c* ?; q7 G
/ b" w2 K. r% w, o *z=x+y;' @ }+ k0 Z& _+ J3 s/ f
) F7 m% ^4 {, f8 v, `
6 ^% H E' ?* ^: o4 u- }" n$ K. g8 f7 E8 A+ Z# ]0 H) s
}
* ?. a2 [$ ?" W# H- |7 C& R, s* y$ {. a( q- N& D
, s% t2 q: y8 K( W& D; }
在这个栗子中,输入参数是x,y,输入参数是z(虽然没有返回)
plhs和prhs其实都是指针数组
prhs[0]代表指向第一个输入数据的指针,mxGetPr代表获得这个指针,后面再加个*就是c语言里面再正常不过的按指针取内容了
所以就这样x,y通过下面这两句传入到了mexFunction中
/ o2 o m% @* X- I) |$ \, d/ G5 d' k2 J( j+ q* D
x = *(mxGetPr(prhs[0]));4 y+ z) W$ `; i
5 }$ x2 {6 b# F* j( L
: S! o8 p8 r6 ^% P* b2 w) h
# a6 O2 D0 Z$ wy = *(mxGetPr(prhs[1]));
( I) v% F0 c5 @) f6 w) s( i' N3 d8 k
2 E" A5 W0 u3 z" B7 c7 X: Z
mxGetPr函数的功能是从指向mxArray类型数据的指针prhs[0]、prhs[1]中获得了指向double类型的指针
另一个函数是mxGetScalar,Scalar即标量,功能是把通过prhs传递进来的mxArray类型数据的指针所指向的数据(标量)赋给c程序里的变量。前面的mxGetPr是传递矢量的,否则矩阵或者向量就没有办法传进来
这里由于传入的每个参数是单个值,于是也可以用mxGetScalar改写:
- 5 }& ?% f, x5 K( S0 r9 X
/ _( S: |$ r# ?% e' R
#include "mex.h" // 使用MEX文件必须包含的头文件 B. R7 ~1 Y+ n: r1 J
, l8 e9 Q, f6 u* g3 O- w5 z
/ ~- B7 Y; N+ n+ ?" F- u( G& Z
4 q4 Z8 \+ p; O3 ~9 u3 a, L: D- r// MEX文件接口函数: }. R m) z+ }& U2 {
, Q- C1 C- T! |9 m! J( X
9 H! x: [# ~. _" U }3 x
* m) W# c4 C4 `, J* `void mexFunction(int nlhs,mxArray *plhs[], int nrhs,const mxArray *prhs[])6 |# d( h) C& g2 x" S e
* K( c- _# B) F
' I6 I) E$ Z; j% X* c1 C1 {8 ~/ K- N5 R8 L+ \% I' B& J* J
{
/ O* X# s8 o! X0 z- n, v% O5 B( m. E0 q" y+ F j
- + T& ?& g1 _; \; F6 c
% d( @ x5 \; F) R
double *z;
' f! Q$ P% _6 Q: F: y0 X3 D4 ?! h, Y4 i6 `1 z5 K& R$ Q, `
- $ U* S% S% c7 N% j. O9 J
) |5 N) E. X0 z( M2 c- _6 r- i
double x, y;! i8 Z& V, k0 D3 P
9 v/ H$ {5 |- K; b5 a
: d( D# S8 r( Q% F) _1 u& y; m# @& s- M( E
plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL);
, V" f- Y! W5 t y# l7 S- k; S# U+ q* C* Q9 s: M* E
% {+ k: y* ?% w& c
* o, }" A6 @) X" j" I0 f z = mxGetPr(plhs[0]);
3 c1 a0 s& X9 r; w0 Q& H% F% W/ V, M6 b
7 r! t4 {$ W3 s; N1 H
" r+ C7 o+ a" E8 S- _. y x = mxGetScalar(prhs[0]));
+ _6 F l7 W" v v
; n" O5 W! @ p5 r& C: v5 i( Y- $ E# p9 G/ j. o2 N: z [5 g$ O
2 q- E; t3 U( R1 P) U0 r y = mxGetScalar(prhs[1]));
T% X& G `# Q1 ^
, F5 {" I7 E% b: q) Q \1 D/ `0 W
. T0 R- ^% C" }/ C. {5 m( k0 X7 H! i7 [& M8 l5 d# }; _
*z=x+y;
( g- T5 }$ }. o' v+ }! \
8 H' x* D0 G. c- Q7 e s; {1 C2 I, I
7 d0 ]% N* G8 U7 h* V) A* T3 e' h) u5 I* Q
}
+ [/ C' |$ f% V
. T! d! _. j- N+ }5 m) {* S+ v- _+ A3 m3 x0 M0 B
(注意:输出参数因为需要通过指针传出,因此这里z必须用mxGetPr这个函数来从mxArray指针获取double指针)
但是这样还是有个问题:如果输入的不是单个的数据,是向量或者矩阵,即使我们通过mxGetPr获得了矩阵或者向量的指针,但是我们假如不知道矩阵的shape,还是不好取值或者计算,所以这里又有两个函数mxGetM和mxGetN可以通过传入参数指针获得传入参数(矩阵)的行和列数。
需要注意的是:
在matlab中矩阵的第一行和第一列的序号是从1开始的,而在c语言中是从0开始的,而且在c语言中的一维数组存储矩阵的数据时,是一列列从上到下,从左到右来存储的,也即
matlab中一个m*n的矩阵M(i,j)对应于c语言中一维数组N中的N[j*m+i]
举个栗子:
& C9 J1 Z/ E) U- P& E: \' J+ s1 h" d! ?
#include "mex.h"6 ?6 z0 y! w3 e
9 J3 a9 h4 r6 l: W
" h! v) z$ [- a) ]
0 ^; ]/ K7 `4 f# _4 L5 ]$ }0 [! Y3 Q void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]){
5 y" A3 Q2 h: o( r2 p2 t! s' p8 B9 ?
' r$ q) L. i" I; b- T( G2 C, E! ^
8 y' ]% O% A% _2 _% p3 u
, N4 @% M) a+ \% N. `
. k7 E7 }1 C7 [/ g: S- n1 Z7 u8 D8 P& |2 O# ? ~
- " s# R+ v$ a# q
8 Z; S1 I3 P; d5 s! F
double *data;, C- S; t; O+ S8 e
" k8 h) _' t! o$ U2 t0 ]% N& B6 _ - & Z' m0 a5 t. p5 h/ w
: n9 O0 x' O+ A7 S" M% f
int M,N;
: K5 j; B: R4 J
: t8 H9 p6 P, G( M8 s. ^
( Z8 @2 q, A( A1 Y
F$ [+ A3 {% s6 ?* b! tint i,j;; s0 u2 f! D) x" o) Y
" _8 p) D" u) x9 N3 w
% d6 \3 h4 O: P8 A* ?
* H" B# D5 u/ h, b7 Tdata=mxGetPr(prhs[0]); //获得指向矩阵的指针 l7 x# |/ \( o9 H( Y
: P1 V' g; k+ Y
- # a: r5 W/ v7 S. b! j% k" h8 |" g* A* W
. {1 G' p& Z u' MM=mxGetM(prhs[0]); //获得矩阵的行数
/ ]$ D7 k. }) o" Q- ~3 q, p, r# F1 ^# ~( |" ~# H
- w; t) p6 a0 ^1 v7 d: T8 U# x7 T( Q3 b& @- {$ r: ^8 R
N=mxGetN(prhs[0]); //获得矩阵的列数
9 q1 Z% H/ K+ Q( b
3 v, [; n" H1 L3 s- & d7 b G7 Z! i! a* _' w
6 v c3 }" ?9 H+ l
for(i=0;i<M;i++)
* t4 I' Y* g2 t+ o4 Z6 I. }, `. `5 Q8 }5 i! ?+ k
! S. e' v! g! H, f6 C, N: ~0 D" p; n
{) R. ?4 f, }+ A9 N9 ]
2 |1 K* p" o& y# r0 E+ J
- " Z+ n! f8 p3 U; M% x1 j' Y
& H9 s8 a$ Y1 d8 x: U for(j=0;j<N;j++): A+ A# f0 A2 q; `$ v7 Y- {
- G+ i9 }: A& H. i! e3 i5 i5 B
* S# v# y1 B2 @. c: ^6 y K. s" T; g: d5 b9 J p8 A. ~
mexPrintf("%4.3f ",data[j*M+i]);
7 D$ z+ t; T+ U$ x5 w; Q0 t
+ L8 j( b2 c$ O/ A& n& J( `' L
9 w0 M, ~) b1 y% ?8 [$ y3 B9 J
7 k9 x7 D: |7 u mexPrintf("\n");
g" |' @0 ] x7 ?3 l& @+ f( {3 G' P
6 Y' |, }- |& k# u1 h/ p( _0 e K8 U; w9 J- j, V4 h/ s: p0 j
}
, q5 \ n( y* I* r2 n$ ^
( i" A, c/ K$ `# o# Y- + w# g: i7 w* _# y' f+ Z5 D5 }
) n" |" d1 D) T7 {- R
}
5 ^3 h! `& N( b5 ^2 E, [6 ^$ d' B2 y+ L0 D+ c( D( m9 [% h
: e; \) b" w, ]" w! W
假如是一个形如[1,2,3;4,5,6]的矩阵,则执行上述后会先后打印出1,4,2,5,3,6
以上讲的都是输入参数,由于输入数据在函数调用前就已经在matlab里申请过内存,由于mex函数与matlab共用一个地址空间,因此通过prhs传递指针即可传入输入参数。但输出参数却需要在mex函数里申请内存,才能将指针放在plhs中传递出去。由于返回指针类似必须是mxArray,所以matlab专门提供了一个函数:mxCreateDoubleMatrix来实现内存申请,函数原型为:
mxArray * mxCreateDoubleMatrix(int m,int n,mxComplexity ComplexFlag)m,n分别是待申请矩阵的行数和列数,需要注意的是为矩阵申请内存后得到的是mxArray类型的指针,就可以放在plhs[]中传递出去了。但是对这个矩阵的处理(包括赋值)却需要在mex函数或者c语言函数中完成,这就需要通过前面的mxGetPr或者mxGetScalar。使用mxGetPr获得指向这个矩阵的double类型指针后,就可以对这个矩阵进行各种操作和运算了。
还是拿这个栗子讲,这里由于输出是一个数,于是m,n都是1,通过mxGetPr进一步获得指向double数据类型指针z
- ' h- C7 _ D; d/ Z3 O! n1 ^4 y0 x8 G
7 ^! K7 e0 G- q9 U+ c+ G
1 }1 N6 S* W9 L
9 n2 b: {* a- E5 p1 I, W0 W. t
$ h' t" @& K% e4 a( h8 p& P- t: k, t2 h4 p7 c
double *z;( D1 a8 @& r3 q" r
2 ? G& \. P( e* Z
! G* h; a/ [8 J8 i6 @- y6 ]; g4 M( `
plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL);. \. r( v/ O6 w g4 }
p: ]. `% w- n! g4 r
( s$ k" [" `/ j# w) G) E: M9 M
8 u+ w3 G# j2 V! w1 R z = mxGetPr(plhs[0]);+ n" g) x( q) G& U" J! ~! V
' o/ d# Y9 A0 t G! w S& T- . d! {6 ~, |9 f
. D$ ~! r7 \: J( ~9 t
x = *(mxGetPr(prhs[0]));
- S5 ^6 K% P& O. B: v3 @# c! p
* v/ H) m/ P3 r* U - % x7 Z x1 p0 D! H% h/ f+ P
8 g! G; d; \1 T$ G0 x6 ] y = *(mxGetPr(prhs[1]));
4 i* Y2 [; X* u, e
7 O2 E% Y& J. }% K
! |: |" F5 L+ s+ d: i. d! F. f: [, n: m/ s5 n% ~
*z=x+y; ]+ J/ |8 w$ T
. @2 \& Y: E" |4 l# _; ~ F; V4 w j6 Y6 Z4 F# `" M
当然,matlab里使用到的并不只是double类型这一种矩阵,还有字符串类型,结构类型矩阵等,并也提供了对应的处理函数。
- p4 X% H; W, F4 ^$ b- x
作者: youOK 时间: 2020-12-10 15:10
matlab与c语言混合编程
| 欢迎光临 EDA365电子论坛网 (https://bbs.eda365.com/) |
Powered by Discuz! X3.2 |