《在MATLAB环境下访问外部函数的共享库文件精品资料.doc》由会员分享,可在线阅读,更多相关《在MATLAB环境下访问外部函数的共享库文件精品资料.doc(21页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、在MATLAB环境下访问外部函数的共享库文件,必须首先把该库文件加载到内存中。一旦加载成功,就能直接在MATLAB中直接请求关于函数的任何信息。而当不再需要该库时,就应当及时把库文件从内存中卸载以节省内存开销。加载库语法:loadlibrary(shrlib,hfile)其中shrlib为加载的动态链接库文件名(filename.dll),hfile为头文件名,它包含函数原型。例如,当加载包含MATLAB中mx程序的libmx库时,可以使用下列语句。hfile=matlabrootexternincludematrix.h;loadlibray(libmx, hfile)卸载库语法:unloa
2、dlibrary libmx使用两个函数可以获取加载库的信息:libfunctions(libname) or libfunctions libnamelibfunctionsview(libname) or libfunctionsview libname这两个函数的不同之处在于显示结果的方式不同,后者是以图形的方式显示在新的窗口中。而前者返回库libmx中有哪些可用的函数。请看示例:libfunctions libmxMethods for class lib.libmx:mxAddField mxGetFieldNumber mxIsLogicalScalarTruemxArrayToS
3、tring mxGetImagData mxIsNaNmxCalcSingleSubscript mxGetInf mxIsNumericmxCalloc mxGetIr mxIsObjectmxClearScalarDoubleFlag mxGetJc mxIsOpaquemxCreateCellArray mxGetLogicals mxIsScalarDoubleFlagSet如果加上命令开头-full,则可以显示函数返回值的细节。libfunctions libmx -fullMethods for class lib.libmx:mxClassID, MATLAB array mxG
4、etClassID(MATLAB array)lib.pointer, MATLAB array mxGetData(MATLAB array)MATLAB array, voidPtr mxSetData(MATLAB array, voidPtr)lib.pointer, MATLAB array mxGetPr(MATLAB array)MATLAB array, doublePtr mxSetPr(MATLAB array, doublePtr)uint8 mxIsFinite(double)uint8 mxIsInf(double)值得注意的是,这两个函数返回值的类型均是MATLAB
5、的数据类型,虽然函数是利用C语言编写的。调用库函数一旦库函数被加载到了内存空间,只要指定库名、函数名和变量就可以使用calllib函数调用库中的任何函数了。语法格式:calllib(libname,funcname,arg1,argn)下列语句显示如何操作:hfile=C:MATLAB7externincludematrix.h;loadlibrary(libmx,hfile);y=rand(4,7,2); %produce a 3D array, there are 56 elements in itcalllib(libmx,mxGetNumberOfElements,y)ans=56Ca
6、lllib(libmx,mxGetClassID,y)ans=mxDouble_CLASS传递变量当调用外部库里的函数时,该为函数提供哪种类型的变量呢?MATLAB的externexamplesshrlibshrlibsample库里对每一种特殊的变量类型都作出了说明。但我们首先必须把该库文件的路径添加到MATLAB的搜索路径中来,或者使该库文件所在的目录成为当前目录,两种做法的命令如下。addpath(C:MATLAB7externexamplesshrlib)cd(C:MATLAB7externexamplesshrlib)下面的例子就是加载该库并显示了其中的一些函数。loadlibrar
7、y shrlibsample shrlibsample.hlibfunctions shrlibsample full执行上述两行后,返回:Functions in library shrlibsample:double, doublePtr addDoubleRef(double, doublePtr, double)double addMixedTypes(int16, int32, double)double, c_structPtr addStructByRef(c_structPtr)double addStructFields(c_struct)c_structPtrPtr all
8、ocateStruct(c_structPtrPtr)voidPtr deallocateStruct(voidPtr)doublePtr multDoubleArray(doublePtr, int32)lib.pointer, doublePtr multDoubleRef(doublePtr)int16Ptr multiplyShort(int16Ptr, int32)string readEnum(Enum1)string, string stringToUpper(string)这里所有的函数都是用C语言编写的。一些通用的规则在函数的输入输出变量问题上,以下几点应注意:1.许多变量类
9、型,象int32、double与C语言的数据类型非常相象。这些变量只需要传递MATLAB型的数据就可以了。2.而有些C语言的变量类型,象*double、还有预定义型与标准MATLAB数据类型是完全不同的。这种情况下,有两种选择,要么给外部函数的入参传递标准的MATLAB数据类型,让MATLAB程序自动转化,要么先使用MATLAB提供的转化函数,如libstruct、libpointer自己转化。关于转化,可以参考Data Conversion。3.C语言通常可以按形参传递变量,但MATLAB不支持这种做法,不过可以创造MATLABPtr或PtrPtr型的变量,去兼容C语言的形参。4.C语言通常
10、还可以通过形参来返回输入变量的值,而MATLAB需要额外的变量来获得返回值。传递变量的通用规则1.库函数传递形参时,标量不必非得声明。2.如果库函数使用单下标来引用二维矩阵元素时,请记住,C语言是逐行处理矩阵元素,而MATLAB是按列优先处理的。因此迎合C语言的习惯,可以在给MATLAB函数传递变量之前把矩阵进行转置,从函数返回后再转置回来就行了。3.由上可知,当传递的矩阵超过二维时,MATLAB会改变矩阵的行列结构,为了确保矩阵的结构不被破坏,可以事先记录矩阵的结构,在调用结束后利用reshape函数还原即可。例如:vs=size(vin); %suppose the dimention o
11、f vector vin is 2-by-5-by2vout=calllib(shrlibsample,multDoubleArray,vin,20); %dimention have been altered ans= 2 10vout=reshape(vout,vs); %Restore the array to 2-by-5-by-2size(vout)ans= 2 5 24.当支持可选参数时,可用一空矩阵来传递一个NULL型参数。这是在变量为Ptr或PtrPtr型时唯一的选择。传参外部库的许多函数是传递形参的,为了能与这些函数交互,MATLAB通常传递一个叫“指针对象”的变量,不过别把
12、它与传参混同了。数据转化在多数情况下,传递给外部库函数或从外部库函数返回的数据类型自动被MATLAB转化,然而,或许你偶尔也希望有些时侯能手动转化:1.当需要传递相同的数据给一系列库函数时,可能手动转化要比让MATLAB自动转化更为明智,更能节省时间。2.当传递大结构的数据时,手动转化数据使之匹配C结构而不是直接采用通用的MATLAB型数据的做法,比直接使用libstruct函数把C结构型的数据转换成MATLAB型数据更能节省内存。3.当外部函数使用超过一层引用(例如,指向指针的指针变量double *)时,用libpointer函数构造一个参数,比直接让MATLAB自动转化数据要好。原始类型
13、共享库接口支持所有标准C数据类型。下表显示了C与MATLAB等价的数据类型。C类型(32位机器)等价MATLAB类型char, byteint8unsigned char, byteuint8shortint16unsigned shortuint16int, longint32unsigned int, unsigned longuint32floatsingledoubledoublechar *string(1-by-n char array)下表显示的lib.pointer类中的数据类型,非MATLAB标准类型C数据类型(32位机器)扩展MATLAB数据类型integer pointe
14、r types (int *)(u) int (size) Ptrfloat *singlePtrdouble *doublePtrmxArray *MATLAB arrayvoid *voidPtrtype *same as typePtr with an added Ptr(e.g.,double * is doublePtrPtr)MATLAB可以自动把转化数据为外部库函数所需要的任何原型数据,这就意味着可以传递一个双精度型数据给一个8位整数型变量。下述C函数接受短整型、整型和双精度型数据:double addMixedTypes(short x, int y, double z) re
15、turn (x+y+z);你可以极其简单地在MATLAB中只传递给该函数以双精度变量,MATLAB自动判断每个变量接受何种类型的变量,并作近似转化。calllib (shrlibsample,addMixedTypes, 127, 33000, pi)ans= 3.3130e+004转化参数当外部函数原型定义一个形参时,MATLAB能自动地把一个按值传递的变量转化为形参。因此,当给一个双精度指针变量赋一双精度变量时,MATLAB会自动地把该双精度变量转化为双精度形参。addDoubleRef是一个接受双精度指针型形参的函数:double addDoubleRef( double x, boub
16、le *y, double z) 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); return input;libfunc
17、tions显示,你可以用一个MATLAB字符串作为输入。libfunctions shrlibsample full string, string stringToUpper (string )定义一个MATLAB字符矩阵str,把它传递给变量。str=This was a Mixed Case string; %MATLAB中字符串以“”号对表示calllib( shrlibsample, stringToUpper, str)ans= THIS WAS A MIXED STRING注意:虽然MATLAB传递给变量的很象字符型的形参,但它并不真正的参数类型。因为它并不包括MATLAB字符矩阵
18、str的地址。因此当函数执行完毕时,字符串的值并未改变。枚举型如果变量被定义为C中的枚举型,你可以传递枚举型或一个与枚举值等价的整数。shrlibsample库中的readEnum函数返回与传入变量相应的枚举型。下述为Enum1的定义和C语言函数readEnum:enum Enum1 en1=1,en2, en4=4 TEnum1;char *readEnum(TEnum1 val) switch (val) case 1:return “you chose en1”; case 2:return “you chose en2”; case 4:return “you chose en4”;
19、default: return “enum not defined”; MATLAB,你可以用一个枚举型字符或等价的整数来表示枚举型数据。上述中定义的枚举型数据TEnum1中,en4与4等价:calllib (shrlibsample, readEnum, en4)ans= you chose en4calllib (shrlibsampel, readEnum, 4)ans= you chose en4结构体型当库函数接受结构体型变量时,你需要给它传递与在结构体定义时拥有相同域名的结构体变量。为了确定结构体变量的域和类型,你可以:1.查询库文档2.在加载到MATLAB的库的头文件中寻找结构体
20、的定义。你也可以在MATLAB中采用下述步骤来确定外部函数定义过的结构体的域名。1.利用libfunctionsview函数来显示正在使用的库函数的信息,它包含了每一个函数所做用的结构体数据的名字。当键入libfunctionsview shrlibsample命令时,MATLAB就会在新窗口中显示库函数的信息。如:double addStructFields (c_struct)2.利用libstruct函数获取结构体定义模型。如s=libstruct( c_struct);3.继而利用get函数返回结构体数据的域名。如get(s) p1:0 p2:0 p3:04.利用calllib函数初始
21、化所需要传递给库函数的域值。如s.p1=478; s.p2=-299; s.p3=1000; calllib (shrlibsample, addStructFields, s)当你利用calllib函数创建或初始化结构体数据时,不必去匹配结构体的数据域,MATLAB会自动转化数据类型。指定结构体域名下面是在为外部库函数传递结构体数据时一般的做法:1.结构体数据可能只包含了定义中很少的一部分域,MATLAB会把其余的域初始化为0.2.你所使用的任何结构体的域名须与定义中的域名一致。3.结构体中不能包含库函数中未定义过的域名。传递MATLAB结构体与其他的数据类型一样,当外部函数接受结构体变量数
22、据类型时,就可以传递一个MATLAB型结构体数据给它。结构体的域名必须与库函数定义中的域名一致,而数值类型则可以不同,由MATLAB自动转换完成。如shrlibsample共享库中定义了这样的C结构和函数:struct c_struct double p1; short p2; long p3; ;double addStructField (struct c_struct st ) double t=st.p1 +st.p2 +st.p3; return t; 下面的代码完成向addStructField函数传递一个结构体变量sm,包含三个双精度数据,即传递的数值类型与C定义中的不一样,但域
23、外必须相同,否则传递不进去:sm.p1=476; sm.p2=-299; sm.p3=1000;calllib(shrlibsample, addStructFields, sm )ans= 1177传递结构体对象当为外部函数传递结构体变量时,MATLAB为了确保传递成功,要求域名必须与库函数定义中的一致,而对数值类型则不加强求,由MATLAB自动转换成库函数中对应域的数值类型,并且把空域的值均初始化为零。当结构体数据较小时,这种做法很有效。然而,当重复传递一个或多个大的结构体数据时,手动转化是更明智的选择,不仅可以节省时间,还可以节省内存和空间。使用libstruct函数s=libstruc
24、t (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=libstru
25、ct (structtype)这种调用格式可以生成域名完整,域值为0的空libstruct对象。使用结构体作为对象libstruct转换后的结构体实际上是lib.c_struct类中的一个对象实例,这一点可以通过whos命令的输出来验证:whos scName Size Bytes Classsc 1-by-1 lib.c_structGrand total is 1 element using 0 bytes域已经被当成了lib.c_struct类的属性来处理了。你可以利用基于对象的函数set和get来读写:sc=libstruct ( c_struct );set (sc, p1,100,
26、 p2, 150, p3, 200 ); %对象读写须用get、setget(sc) p1:100 p2:150 p3:200但是你也可以象处理结构体数据那样简单地对sc进行读写:sc.p1=23; %而结构体的域可以直接赋值sc.p1ans= 23创建形参你可以为外部函数按值传递大多数的变量,即使函数原型要求形参传递,然而有时你会发现这与直接给C传递形参一样揍效。使用库指针函数用函数libpointer构造一个形参的语法如下:p=libpointer(type, value)例如要创建一个指向int16数据类型的指针pv,就得先指定指针的类型,并以Ptr作后缀:v=int16(485);pv
27、=libpointer(int16Prt, v);返回值pv实际就是MATLAB中lib.pointer类的一个实例。lib.pointer有属性值和数据类型。你可以用get或set函数来读或写这些属性。get(pv) value:485DataType:int16Ptrlib.pointer类还有另外两种方法setdatatype和reshape。methods(pv)methods for class lib.pointer:setdatatype reshape为原始类型创建形参如何去创建和传递指针给双精度型,又如何输出数据这里有一个简单的例子可以说明。函数multDoubleRef接受
28、一个双精度形参同时返回双精度型。double *multDoubleRef(double *x) *x *=5; return x;输入数据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的属性值,但它并不修
29、改x的值。获得函数的返回值在上述最后一例子中,从MATLAB调用的函数返回值可以通过检查修改了的输入形参来获得,但这个函数也可以通过输出变量来获得。这个函数的MATLAB原型表明(利用libfunctions shrlibsample full查看原型),它返回了两个输出变量,一为lib.pointer类的对象,另一为dlublePtr输入变量的属性值:libfunctions shrlibsample fulllib.pointer, doublePtr multDoubleRef (doublePtr)再次运行这个例程,但这次检查返回值x=15;xp=libpointer( doubleP
30、tr, x);xobj, xval=calllib(shrlibsample, multDoubleRef, xp)xobj= lib.pointerxval= 75创建结构体形参与创建原始类型的形参相比,创建结构体的形参并非难事。下述函数只接受C语言形式的结构体形参,它的返回值是所有结构体域值之和,同时也修改了输入参量。double addStructByRef( struct c_struct *st ) double t=st-p1+st-p2+st-p3; st-p1=5.5; st-p2=1234; st-p3=12345678; return t;(1)传递结构体本身虽然这个函数期
31、望获得一个结构体的输入参量。下列给形参传递了一个MATLAB的结构体sm,返回值是正确的,因为sm不是按址传递,所以sm的域值并未被函数修改。sm.p1=476; sm.p2=-299; sm.p3=1000;x=calllib(shrlibsample, addStructByRef, sm)x= 1177(2)传递结构体形参sp=libpointer( c_struct, sm);calllib(shrlibsample, addStructByRef, sp )ans= 1177get(sp,value)ans= p1:5.5000 p2:1234 p3:12345678形参指针当变量超
32、过一层引用(例如,uint16 *)就是这里提到的形参指针。在MATLAB中,这类变量类型都加以后缀PtrPtr。当调用一个接受形参指针的函数时,你可以使用一个形参变量代替,MATLAB将会把该形参变量转换为形参指针。例如,外部函数allocateStruct接受一个c_structPtrPtr变量:libfunctions shrlibsample full c_structPtrPtr allocateStruct(c_structPrtPtr)C语言编写的该函数:void allocateStruct (struct c_struct *val) *val=(struct c_struc
33、t *) malloc(sizeof(sturct c_struct); (*val)-p1=12.4; (*val)-p2=222; (*val)-p3=333333;该函数原型需要一个c_structPtrPtr型数据,但你可以只传递一个c_structPtr型数据,让MATLAB完成第二层引用。下例创建了一个空的结构体形参传递给allocateStruct函数:sp=libpointer (c_structPtr);calllib( shrlibsample, allocateStruct, sp)get(sp)ans= value:1-by-1 struct DataType:c_st
34、ructPtrget(sp, value)ans= p1:12.4000 p2:222 p3:333333完成之后,记得从内存中删除该对象以释放空间:calllib( shrlibsample, deallocateStruct, sp)MATLAB外部接口你可以在MATLAB中调用自己编写的C函数,MATLAB会让你感觉就象调用MATLAB自身内建函数一样轻松。MATLAB中可以调用的C函数就是MEX文件,MEX文件是MATLAB解释器能自动加载和执行的子程序。MEX文件有几个应用:1.不必为调用大型C程序而把它改写成MATLAB默认的M文件。2.解决计算的一些瓶颈问题,在MATLAB中做一
35、些循环计算时效率不如C语言。MEX文件不适合所有的应用,MATLAB是一个高效率的系统,与C和Fortan编译相比,它能有效降低耗时。一般多数编程MATLAB均能解决,因此除非你的应用程序确实需要MEX文件,否则不必使用MEX文件。使用MEX文件MEX文件是C或Fortran代码的子程序,它的运行就象M文件和内建函数。MATLAB识别MEX文件是根据不同操作平台文件的扩展名,而M文件的扩展名(.m)与操作平台无关。不如操作系统下MEX文件的扩展名如下:操作系统平台MEX文件扩展名HP-UXmexhpuxLinuxmexglxMacintoshmexmacSolarismexsolWindows
36、dll你可以准确地调用MEX文件就如同调用M文件。例如,磁盘的datafun toolbox目录上有一conv2.mex的MEX文件,它能实现一个二维矩阵的转换,而conv2.m文件只包含帮助文档。如果从MATLAB内部调用函数conv2,解释器将在MATLAB的搜索路径(默认的路径有多条)上查找,直至找到第一次出现的conv2的文件和相应的扩展名,然后加载并执行。如果在同一目录上有相同文件名的MEX文件(.dll-以windows平台为例)和M文件(.m),则MEX文件优先,而帮助文档仍然从.m文件中读取。前缀mx与mex的差别API的程序以mx为前缀,允许你创建、访问、操作和销毁mxArr
37、ays,前缀mex的程序在MATLAB的后台工作。例如mexEvalString子程序就工作在MATLAB的工作空间对字符串运算。为了操作MATLAB的矩阵,矩阵访问和创建库提供一套子程序,这些子程序以mx前缀开头,它们的完整文档于在线参考网页上能找到。例如,mxGetPi函数从矩阵内取回虚数的指针。虽然访问、创建矩阵的子程序允许操纵MATLAB矩阵,但有两种情况例外,IEEE程序和内存管理程序。例如,mxGetNaN返回一双精度数据,而非mxArray型。MATLAB数据在你开始编制MEX文件之前,必须先了解MATLAB支持的数据类型。1.矩阵MATLAB只用唯一的对象类型数据-MATLAB
38、矩阵。所有的MATLAB变量,包括标量、矢量、矩阵、字符串、元胞矩阵、结构体及对象,它们都是存储在MATLAB矩阵里。对应C语言中,MATLAB矩阵应声明为mxArray型,mxArray型数据中包括了矩阵的类型、维数、相关数据等。如果是数值变量,它还包括该变量是实数还是复数的信息,如果是稀疏矩阵,它还记录下标和非零的元素个数,如果是结构体或对象,它还包括域的个数和域名。2.数据存储MATLAB中的数据是按列存储,与Fortran相同,之所以采用这种习惯,是缘于MATLAB最初是用Fortran语言编写的。例如矩阵a=house; floor; porcha= house floor porc
39、hsize(a)ans= 3 5数据存储为hfpolouorsocerh3.复数复数在MATLAB中是最普遍的双精度类型,一个m-by-n的矩阵它的实部和虚部分别存放在m-by-n大小的矩阵中,其中m表示矩阵的行数,n表示矩阵的列数。这两个矩阵独立时由两个指向实数和虚数的指针pr、pi指着,如果是实数(如单精度的浮点数,无符号和有符号的8、16、32位整数),则虚部的指针为NULL。4.逻辑矩阵5.MATLAB字符串 MATLAB字符串是字符类型,它的存储方式与16位整数一样,只是没有虚部分量。与C不同的是,MATLAB字符串不以NULL结束。6.元胞矩阵7.稀疏矩阵稀疏矩阵的存储习惯与满置矩
40、阵不同,除了指向实部和虚部的指针pr、pi外,还有三个参数nzmax、ir和jc:nzmax 为一整数,它包括ir、pr的长度,如果有虚部的话,也包括pi的长度,它表示稀疏矩阵中不为零的元素的最大的个数。ir 是一长度为nzmax的整数矩阵,它包含了pr和pi指针中相应元素的行下标。jc是一长度为N+1的整数矩阵,它包含了元素列的信息。j的变化范围是0=ja1,1ans =cellclassa1,2ans = 1 2 2a2,:ans =abcans = 9 5 6 b=a1,1b =cellclass元胞数组:元胞数组是MATLAB的一种特殊数据类型,可以将元胞数组看做一种无所不包的通用矩阵
41、,或者叫做广义矩阵。组成元胞数组的元素可以是任何一种数据类型的常数或者常量,每一个元素也可以具有不同的尺寸和内存占用空间,每一个元素的内容也可以完全不同,所以元胞数组的元素叫做元胞(cell)。和一般的数值矩阵一样,元胞数组的内存空间也是动态分配的。(1)元胞数组的创建 a=matlab,20;ones(2,3),1:10a = matlab 20 2x3 double 1x10 double b=matlab,20;ones(2,3),1:10b = matlab 20 2x3 double 1x10 double c=10c = 10c(1,2)=2c = 10 2c(2,2)=5c = 10 2 5isequal(a,b)ans = 1whosName Size Bytes Class Attributesa 2x2 388 cell ans 1x1 1 logical