在MATLAB环境下访问外部函数的共享库文件.docx
《在MATLAB环境下访问外部函数的共享库文件.docx》由会员分享,可在线阅读,更多相关《在MATLAB环境下访问外部函数的共享库文件.docx(20页珍藏版)》请在冰豆网上搜索。
在MATLAB环境下访问外部函数的共享库文件
在MATLAB环境下访问外部函数的共享库文件,必须首先把该库文件加载到内存中。
一旦加载成功,就能直接在MATLAB中直接请求关于函数的任何信息。
而当不再需要该库时,就应当及时把库文件从内存中卸载以节省内存开销。
加载库
语法:
loadlibrary(‘shrlib’,’hfile’)
其中shrlib为加载的动态链接库文件名(filename.dll),hfile为头文件名,它包含函数原型。
例如,当加载包含MATLAB中mx程序的libmx库时,可以使用下列语句。
hfile=[matlabroot’\extern\include\matrix.h’];
loadlibray(‘libmx’,hfile)
卸载库
语法:
unloadlibrarylibmx
使用两个函数可以获取加载库的信息:
libfunctions(‘libname’)orlibfunctionslibname
libfunctionsview(‘libname’)orlibfunctionsviewlibname
这两个函数的不同之处在于显示结果的方式不同,后者是以图形的方式显示在新的窗口中。
而前者返回库libmx中有哪些可用的函数。
请看示例:
libfunctionslibmx
Methodsforclasslib.libmx:
mxAddFieldmxGetFieldNumbermxIsLogicalScalarTrue
mxArrayToStringmxGetImagDatamxIsNaN
mxCalcSingleSubscriptmxGetInfmxIsNumeric
mxCallocmxGetIrmxIsObject
mxClearScalarDoubleFlagmxGetJcmxIsOpaque
mxCreateCellArraymxGetLogicalsmxIsScalarDoubleFlagSet
如果加上命令开头-full,则可以显示函数返回值的细节。
libfunctionslibmx-full
Methodsforclasslib.libmx:
[mxClassID,MATLABarray]mxGetClassID(MATLABarray)
[lib.pointer,MATLABarray]mxGetData(MATLABarray)
[MATLABarray,voidPtr]mxSetData(MATLABarray,voidPtr)
[lib.pointer,MATLABarray]mxGetPr(MATLABarray)
[MATLABarray,doublePtr]mxSetPr(MATLABarray,doublePtr)
uint8mxIsFinite(double)
uint8mxIsInf(double)
值得注意的是,这两个函数返回值的类型均是MATLAB的数据类型,虽然函数是利用C语言编写的。
调用库函数
一旦库函数被加载到了内存空间,只要指定库名、函数名和变量就可以使用calllib函数调用库中的任何函数了。
语法格式:
calllib(‘libname’,’funcname’,arg1,…,argn)
下列语句显示如何操作:
hfile=['C:
\MATLAB7\extern\include\matrix.h'];
loadlibrary(‘libmx’,hfile);
y=rand(4,7,2);%producea3Darray,thereare56elementsinit
calllib(‘libmx’,’mxGetNumberOfElements’,y)
ans=
56
Calllib(‘libmx’,’mxGetClassID’,y)
ans=
mxDouble_CLASS
传递变量
当调用外部库里的函数时,该为函数提供哪种类型的变量呢?
MATLAB的extern\examples\shrlib\shrlibsample库里对每一种特殊的变量类型都作出了说明。
但我们首先必须把该库文件的路径添加到MATLAB的搜索路径中来,或者使该库文件所在的目录成为当前目录,两种做法的命令如下。
addpath(‘C:
\MATLAB7\extern\examples\shrlib’)
cd(‘C:
\MATLAB7\extern\examples\shrlib’)
下面的例子就是加载该库并显示了其中的一些函数。
loadlibraryshrlibsampleshrlibsample.h
libfunctionsshrlibsample–full
执行上述两行后,返回:
Functionsinlibraryshrlibsample:
[double,doublePtr]addDoubleRef(double,doublePtr,double)
doubleaddMixedTypes(int16,int32,double)
[double,c_structPtr]addStructByRef(c_structPtr)
doubleaddStructFields(c_struct)
c_structPtrPtrallocateStruct(c_structPtrPtr)
voidPtrdeallocateStruct(voidPtr)
doublePtrmultDoubleArray(doublePtr,int32)
[lib.pointer,doublePtr]multDoubleRef(doublePtr)
int16PtrmultiplyShort(int16Ptr,int32)
stringreadEnum(Enum1)
[string,string]stringToUpper(string)
这里所有的函数都是用C语言编写的。
一些通用的规则
在函数的输入输出变量问题上,以下几点应注意:
1.许多变量类型,象int32、double与C语言的数据类型非常相象。
这些变量只需要传递MATLAB型的数据就可以了。
2.而有些C语言的变量类型,象**double、还有预定义型与标准MATLAB数据类型是完全不同的。
这种情况下,有两种选择,要么给外部函数的入参传递标准的MATLAB数据类型,让MATLAB程序自动转化,要么先使用MATLAB提供的转化函数,如libstruct、libpointer自己转化。
关于转化,可以参考DataConversion。
3.C语言通常可以按形参传递变量,但MATLAB不支持这种做法,不过可以创造MATLABPtr或PtrPtr型的变量,去兼容C语言的形参。
4.C语言通常还可以通过形参来返回输入变量的值,而MATLAB需要额外的变量来获得返回值。
传递变量的通用规则
1.库函数传递形参时,标量不必非得声明。
2.如果库函数使用单下标来引用二维矩阵元素时,请记住,C语言是逐行处理矩阵元素,而MATLAB是按列优先处理的。
因此迎合C语言的习惯,可以在给MATLAB函数传递变量之前把矩阵进行转置,从函数返回后再转置回来就行了。
3.由上可知,当传递的矩阵超过二维时,MATLAB会改变矩阵的行列结构,为了确保矩阵的结构不被破坏,可以事先记录矩阵的结构,在调用结束后利用reshape函数还原即可。
例如:
vs=size(vin);%supposethedimentionofvectorvinis2-by-5-by2
vout=calllib(‘shrlibsample’,’multDoubleArray’,vin,20);%dimentionhavebeenaltered
ans=
210
vout=reshape(vout,vs);%Restorethearrayto2-by-5-by-2
size(vout)
ans=
252
4.当支持可选参数时,可用一空矩阵来传递一个NULL型参数。
这是在变量为Ptr或PtrPtr型时唯一的选择。
传参
外部库的许多函数是传递形参的,为了能与这些函数交互,MATLAB通常传递一个叫“指针对象”的变量,不过别把它与传参混同了。
数据转化
在多数情况下,传递给外部库函数或从外部库函数返回的数据类型自动被MATLAB转化,然而,或许你偶尔也希望有些时侯能手动转化:
1.当需要传递相同的数据给一系列库函数时,可能手动转化要比让MATLAB自动转化更为明智,更能节省时间。
2.当传递大结构的数据时,手动转化数据使之匹配C结构而不是直接采用通用的MATLAB型数据的做法,比直接使用libstruct函数把C结构型的数据转换成MATLAB型数据更能节省内存。
3.当外部函数使用超过一层引用(例如,指向指针的指针变量double**)时,用libpointer函数构造一个参数,比直接让MATLAB自动转化数据要好。
原始类型
共享库接口支持所有标准C数据类型。
下表显示了C与MATLAB等价的数据类型。
C类型(32位机器)
等价MATLAB类型
char,byte
int8
unsignedchar,byte
uint8
short
int16
unsignedshort
uint16
int,long
int32
unsignedint,unsignedlong
uint32
float
single
double
double
char*
string(1-by-nchararray)
下表显示的lib.pointer类中的数据类型,非MATLAB标准类型
C数据类型(32位机器)
扩展MATLAB数据类型
integerpointertypes(int*)
(u)int(size)Ptr
float*
singlePtr
double*
doublePtr
mxArray*
MATLABarray
void*
voidPtr
type**
sameastypePtrwithanaddedPtr(e.g.,double**isdoublePtrPtr)
MATLAB可以自动把转化数据为外部库函数所需要的任何原型数据,这就意味着可以传递一个双精度型数据给一个8位整数型变量。
下述C函数接受短整型、整型和双精度型数据:
doubleaddMixedTypes(shortx,inty,doublez)
{
return(x+y+z);
}
你可以极其简单地在MATLAB中只传递给该函数以双精度变量,MATLAB自动判断每个变量接受何种类型的变量,并作近似转化。
calllib(‘shrlibsample’,’addMixedTypes’,127,33000,pi)
ans=
3.3130e+004
转化参数
当外部函数原型定义一个形参时,MATLAB能自动地把一个按值传递的变量转化为形参。
因此,当给一个双精度指针变量赋一双精度变量时,MATLAB会自动地把该双精度变量转化为双精度形参。
addDoubleRef是一个接受双精度指针型形参的函数:
doubleaddDoubleRef(doublex,bouble*y,doublez)
{
return(x+*y+z);
}
用三个双精度变量调用该函数,MATLAB自动处理数据转化:
calllib(‘shrlibsample’,‘addDoubleRef’,1.78,5.42,13.3)
ans=
20.5000
字符串
当变量需要字符型指针数据时,你可以传递一个MATLAB型字符串(矩阵)。
下述C函数接受一个字符指针型数据:
char*stringToUpper(char*input)
{
char*p=input;
if(p!
=NULL)
while(*p!
=0)
*p++=toupper(*p);
returninput;
}
libfunctions显示,你可以用一个MATLAB字符串作为输入。
libfunctionsshrlibsample–full
[string,string]stringToUpper(string)
定义一个MATLAB字符矩阵str,把它传递给变量。
str=’ThiswasaMixedCasestring’;%MATLAB中字符串以“’”号对表示
calllib(‘shrlibsample’,‘stringToUpper’,str)
ans=
THISWASAMIXEDSTRING
注意:
虽然MATLAB传递给变量的很象字符型的形参,但它并不真正的参数类型。
因为它并不包括MATLAB字符矩阵str的地址。
因此当函数执行完毕时,字符串的值并未改变。
枚举型
如果变量被定义为C中的枚举型,你可以传递枚举型或一个与枚举值等价的整数。
shrlibsample库中的readEnum函数返回与传入变量相应的枚举型。
下述为Enum1的定义和C语言函数readEnum:
enumEnum1{en1=1,en2,en4=4}TEnum1;
char*readEnum(TEnum1val)
{
switch(val){
case1:
return“youchoseen1”;
case2:
return“youchoseen2”;
case4:
return“youchoseen4”;
default:
return“enumnotdefined”;
}
}
MATLAB,你可以用一个枚举型字符或等价的整数来表示枚举型数据。
上述中定义的枚举型数据TEnum1中,en4与4等价:
calllib(‘shrlibsample’,‘readEnum’,‘en4’)
ans=
youchoseen4
calllib(‘shrlibsampel’,‘readEnum’,4)
ans=
youchoseen4
结构体型
当库函数接受结构体型变量时,你需要给它传递与在结构体定义时拥有相同域名的结构体变量。
为了确定结构体变量的域和类型,你可以:
1.查询库文档
2.在加载到MATLAB的库的头文件中寻找结构体的定义。
你也可以在MATLAB中采用下述步骤来确定外部函数定义过的结构体的域名。
1.利用libfunctionsview函数来显示正在使用的库函数的信息,它包含了每一个函数所做用的结构体数据的名字。
当键入libfunctionsviewshrlibsample命令时,MATLAB就会在新窗口中显示库函数的信息。
如:
doubleaddStructFields(c_struct)
2.利用libstruct函数获取结构体定义模型。
如s=libstruct(‘c_struct’);
3.继而利用get函数返回结构体数据的域名。
如get(s)
p1:
0
p2:
0
p3:
0
4.利用calllib函数初始化所需要传递给库函数的域值。
如s.p1=478;s.p2=-299;s.p3=1000;
calllib(‘shrlibsample’,‘addStructFields’,s)
当你利用calllib函数创建或初始化结构体数据时,不必去匹配结构体的数据域,MATLAB会自动转化数据类型。
指定结构体域名
下面是在为外部库函数传递结构体数据时一般的做法:
1.结构体数据可能只包含了定义中很少的一部分域,MATLAB会把其余的域初始化为0.
2.你所使用的任何结构体的域名须与定义中的域名一致。
3.结构体中不能包含库函数中未定义过的域名。
传递MATLAB结构体
与其他的数据类型一样,当外部函数接受结构体变量数据类型时,就可以传递一个MATLAB型结构体数据给它。
结构体的域名必须与库函数定义中的域名一致,而数值类型则可以不同,由MATLAB自动转换完成。
如shrlibsample共享库中定义了这样的C结构和函数:
structc_struct{
doublep1;
shortp2;
longp3;
};
doubleaddStructField(structc_structst)
{
doublet=st.p1+st.p2+st.p3;
returnt;
}
下面的代码完成向addStructField函数传递一个结构体变量sm,包含三个双精度数据,即传递的数值类型与C定义中的不一样,但域外必须相同,否则传递不进去:
sm.p1=476;sm.p2=-299;sm.p3=1000;
calllib(‘shrlibsample’,‘addStructFields’,sm)
ans=
1177
传递结构体对象
当为外部函数传递结构体变量时,MATLAB为了确保传递成功,要求域名必须与库函数定义中的一致,而对数值类型则不加强求,由MATLAB自动转换成库函数中对应域的数值类型,并且把空域的值均初始化为零。
当结构体数据较小时,这种做法很有效。
然而,当重复传递一个或多个大的结构体数据时,手动转化是更明智的选择,不仅可以节省时间,还可以节省内存和空间。
使用libstruct函数
s=libstruct(‘structtype’,mlstruct)
返回值s叫做libstruct对象。
虽然它实际上是MATLAB的一个对象,但它更象是一个结构体数据。
这个新的所谓“结构体”的域名得自于外部库函数中结构体的域名。
例如,把MATLAB结构体sm转换成libstruct对象sc:
sm.p1=476;sm.p2=-299;sm.p3=1000;
sc=libstruct(‘c_struct’,sm);
sm的原始结构中域值为三个双精度型,而libstruct函数转换后的sc对象的域名则与c_struct结构体一致,分别为double、short和long型。
创建空libstruct对象
s=libstruct(‘structtype’)这种调用格式可以生成域名完整,域值为0的空libstruct对象。
使用结构体作为对象
libstruct转换后的结构体实际上是lib.c_struct类中的一个对象实例,这一点可以通过whos命令的输出来验证:
whossc
NameSizeBytesClass
sc1-by-1lib.c_struct
Grandtotalis1elementusing0bytes
域已经被当成了lib.c_struct类的属性来处理了。
你可以利用基于对象的函数set和get来读写:
sc=libstruct(‘c_struct’);
set(sc,‘p1’,100,‘p2’,150,‘p3’,200);%对象读写须用get、set
get(sc)
p1:
100
p2:
150
p3:
200
但是你也可以象处理结构体数据那样简单地对sc进行读写:
sc.p1=23;%而结构体的域可以直接赋值
sc.p1
ans=
23
创建形参
你可以为外部函数按值传递大多数的变量,即使函数原型要求形参传递,然而有时你会发现这与直接给C传递形参一样揍效。
使用库指针函数
用函数libpointer构造一个形参的语法如下:
p=libpointer(‘type’,‘value’)
例如要创建一个指向int16数据类型的指针pv,就得先指定指针的类型,并以Ptr作后缀:
v=int16(485);
pv=libpointer(‘int16Prt’,v);
返回值pv实际就是MATLAB中lib.pointer类的一个实例。
lib.pointer有属性值和数据类型。
你可以用get或set函数来读或写这些属性。
get(pv)
value:
485
DataType:
’int16Ptr’
lib.pointer类还有另外两种方法setdatatype和reshape。
methods(pv)
methodsforclasslib.pointer:
setdatatypereshape
为原始类型创建形参
如何去创建和传递指针给双精度型,又如何输出数据这里有一个简单的例子可以说明。
函数multDoubleRef接受一个双精度形参同时返回双精度型。
double*multDoubleRef(double*x)
{
*x*=5;
returnx;
}
输入数据x来创建一个形参xp:
x=15;
xp=libpointer(‘doublePtr’,x);
get(xp)
value:
15
Datatype:
’doublePtr’
现在可以调用函数来检验结果:
calllib(‘shrlibsample’,‘multDoubleRef’,xp);
get(xp,‘value’)
ans=
75
注意:
xp虽然是作为x的形参而创建的,但它并非真的象C语言的指针,因为xp中并不包含x的地址,因此,当函数执行时,函数修改xp的属性值,但它并不修改x的值。
获得函数的返回值
在上述最后一例子中,从MATLAB调用的函数返回值可以通过检查修改了的输入形参来获得,但这个函数也可以通过输出变量来获得。
这个函数的MATLAB原型表明(利用libfunctionsshrlibsample–full查看原型),它返回了两个输出变量,一为lib.pointer类的对象,另一为dlublePtr输入变量的属性值:
libfunctionsshrlibsample–full
[lib.pointer,doublePtr]multDoubleRef(doublePtr)
再次运行这个例程,但这次检查返回值
x=15;
xp=libpointer(‘doublePtr’,x);
[xobj,xval]=calllib(‘shrlibsample’,‘multDoubleRef’,xp)
xobj=
lib.pointer
xval=
75
创建结构体形参
与创建原始类型的形参相比,创建结构体的形参并非难事。
下述函数只接受C语言形式的结构体形参,它的返回值是所有结构体域值之和,同时也修改了输入参量。
doubleaddStructByRef(structc_struct*st)
{
doublet=st->p1+st->p2+st->p3;
st->p1=5.5;
st->p2=1234;
st->p3=12345678;
returnt;
}
(1)传递结构体本身
虽然这个函数期望获得一个结构体的输入参量。
下列给形参传递了一个MATLAB的结构体sm,返回值是正确的,因为sm不是按址传递,所以sm的域值并未被函数修改。
sm.p1=476;sm.p2=-299;sm.p3=1000;
x=calllib(‘sh