在MATLAB环境下访问外部函数的共享库文件,必须首先把该库文件加载到内存中。一旦加载成功,就能直接在MATLAB中直接请求关于函数的任何信息。而当不再需要该库时,就应当及时把库文件从内存中卸载以节省内存开销。
加载库
语法:loadlibrary(‘shrlib’,’hfile’)
其中shrlib为加载的动态链接库文件名(filename.dll),hfile为头文件名,它包含函数原型。例如,当加载包含MATLAB中mx程序的libmx库时,可以使用下列语句。
hfile=[matlabroot’externincludematrix.h’];
loadlibray(‘libmx’, hfile)
卸载库
语法:unloadlibrary libmx
使用两个函数可以获取加载库的信息:
libfunctions(‘libname’) or libfunctions libname
libfunctionsview(‘libname’) or libfunctionsview libname
这两个函数的不同之处在于显示结果的方式不同,后者是以图形的方式显示在新的窗口中。而前者返回库libmx中有哪些可用的函数。请看示例:
libfunctions libmx
Methods for class lib.libmx:
mxAddField mxGetFieldNumber mxIsLogicalScalarTrue
mxArrayToString mxGetImagData mxIsNaN
mxCalcSingleSubscript mxGetInf mxIsNumeric
mxCalloc mxGetIr mxIsObject
mxClearScalarDoubleFlag mxGetJc mxIsOpaque
mxCreateCellArray mxGetLogicals mxIsScalarDoubleFlagSet
如果加上命令开头-full,则可以显示函数返回值的细节。
libfunctions libmx -full
Methods for class lib.libmx:
[mxClassID, MATLAB array] mxGetClassID(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的数据类型,虽然函数是利用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 it
calllib(‘libmx’,’mxGetNumberOfElements’,y)
ans=
56
Calllib(‘libmx’,’mxGetClassID’,y)
ans=
mxDouble_CLASS
传递变量
当调用外部库里的函数时,该为函数提供哪种类型的变量呢?MATLAB的externexamplesshrlibshrlibsample库里对每一种特殊的变量类型都作出了说明。但我们首先必须把该库文件的路径添加到MATLAB的搜索路径中来,或者使该库文件所在的目录成为当前目录,两种做法的命令如下。
addpath(‘C:MATLAB7externexamplesshrlib’)
cd(‘C:MATLAB7externexamplesshrlib’)
下面的例子就是加载该库并显示了其中的一些函数。
loadlibrary shrlibsample shrlibsample.h
libfunctions 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 allocateStruct(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.许多变量类型,象int32、double与C语言的数据类型非常相象。这些变量只需要传递MATLAB型的数据就可以了。
2.而有些C语言的变量类型,象**double、还有预定义型与标准MATLAB数据类型是完全不同的。这种情况下,有两种选择,要么给外部函数的入参传递标准的MATLAB数据类型,让MATLAB程序自动转化,要么先使用MATLAB提供的转化函数,如libstruct、libpointer自己转化。关于转化,可以参考Data Conversion。
3.C语言通常可以按形参传递变量,但MATLAB不支持这种做法,不过可以创造MATLABPtr或PtrPtr型的变量,去兼容C语言的形参。
4.C语言通常还可以通过形参来返回输入变量的值,而MATLAB需要额外的变量来获得返回值。
传递变量的通用规则
1.库函数传递形参时,标量不必非得声明。
2.如果库函数使用单下标来引用二维矩阵元素时,请记住,C语言是逐行处理矩阵元素,而MATLAB是按列优先处理的。因此迎合C语言的习惯,可以在给MATLAB函数传递变量之前把矩阵进行转置,从函数返回后再转置回来就行了。
3.由上可知,当传递的矩阵超过二维时,MATLAB会改变矩阵的行列结构,为了确保矩阵的结构不被破坏,可以事先记录矩阵的结构,在调用结束后利用reshape函数还原即可。例如:
vs=size(vin); %suppose the dimention of vector vin is 2-by-5-by2
vout=calllib(‘shrlibsample’,’multDoubleArray’,vin,20); %dimention have been altered
ans=
2 10
vout=reshape(vout,vs); %Restore the array to 2-by-5-by-2
size(vout)
ans=
2 5 2
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 |
unsigned char, byte | uint8 |
short | int16 |
unsigned short | uint16 |
int, long | int32 |
unsigned int, unsigned long | uint32 |
float | single |
double | double |
char * | string(1-by-n char array) |
下表显示的lib.pointer类中的数据类型,非MATLAB标准类型
C数据类型(32位机器) | 扩展MATLAB数据类型 |
integer pointer types (int *) | (u) int (size) Ptr |
float * | singlePtr |
double * | doublePtr |
mxArray * | MATLAB array |
void * | voidPtr |
type ** | same as typePtr with an added Ptr(e.g.,double ** is doublePtrPtr) |
MATLAB可以自动把转化数据为外部库函数所需要的任何原型数据,这就意味着可以传递一个双精度型数据给一个8位整数型变量。下述C函数接受短整型、整型和双精度型数据:
double addMixedTypes(short x, int y, double z)
{
return (x+y+z);
}
你可以极其简单地在MATLAB中只传递给该函数以双精度变量,MATLAB自动判断每个变量接受何种类型的变量,并作近似转化。
calllib (‘shrlibsample’,’addMixedTypes’, 127, 33000, pi)
ans=
3.3130e+004
转化参数
当外部函数原型定义一个形参时,MATLAB能自动地把一个按值传递的变量转化为形参。因此,当给一个双精度指针变量赋一双精度变量时,MATLAB会自动地把该双精度变量转化为双精度形参。
addDoubleRef是一个接受双精度指针型形参的函数:
double addDoubleRef( double x, bouble *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;
}
libfunctions显示,你可以用一个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字符矩阵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”;
default: return “enum not defined”;
}
}
MATLAB,你可以用一个枚举型字符或等价的整数来表示枚举型数据。上述中定义的枚举型数据TEnum1中,en4与4等价:
calllib (‘shrlibsample’, ‘readEnum’, ‘en4’)
ans=
you chose en4
calllib (‘shrlibsampel’, ‘readEnum’, 4)
ans=
you chose en4
结构体型
当库函数接受结构体型变量时,你需要给它传递与在结构体定义时拥有相同域名的结构体变量。为了确定结构体变量的域和类型,你可以:
1.查询库文档
2.在加载到MATLAB的库的头文件中寻找结构体的定义。
你也可以在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: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结构和函数:
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定义中的不一样,但域外必须相同,否则传递不进去:
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命令的输出来验证:
whos sc
Name Size Bytes Class
sc 1-by-1 lib.c_struct
Grand total is 1 element using 0 bytes
域已经被当成了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)
methods for class lib.pointer:setdatatype reshape
为原始类型创建形参
如何去创建和传递指针给双精度型,又如何输出数据这里有一个简单的例子可以说明。函数multDoubleRef接受一个双精度形参同时返回双精度型。
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的属性值,但它并不修改x的值。
获得函数的返回值
在上述最后一例子中,从MATLAB调用的函数返回值可以通过检查修改了的输入形参来获得,但这个函数也可以通过输出变量来获得。
这个函数的MATLAB原型表明(利用libfunctions shrlibsample –full查看原型),它返回了两个输出变量,一为lib.pointer类的对象,另一为dlublePtr输入变量的属性值:
libfunctions shrlibsample –full
[lib.pointer, doublePtr] multDoubleRef (doublePtr)
再次运行这个例程,但这次检查返回值
x=15;
xp=libpointer(‘ doublePtr’, x);
[xobj, xval]=calllib(‘shrlibsample’, ‘multDoubleRef’, xp)
xobj=
lib.pointer
xval=
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)传递结构体本身
虽然这个函数期望获得一个结构体的输入参量。下列给形参传递了一个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=
1177
get(sp,’value’)
ans=
p1:5.5000
p2:1234
p3:12345678
形参指针
当变量超过一层引用(例如,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_struct *) 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_structPtr’
get(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中做一些循环计算时效率不如C语言。
MEX文件不适合所有的应用,MATLAB是一个高效率的系统,与C和Fortan编译相比,它能有效降低耗时。一般多数编程MATLAB均能解决,因此除非你的应用程序确实需要MEX文件,否则不必使用MEX文件。
使用MEX文件
MEX文件是C或Fortran代码的子程序,它的运行就象M文件和内建函数。MATLAB识别MEX文件是根据不同操作平台文件的扩展名,而M文件的扩展名(.m)与操作平台无关。不如操作系统下MEX文件的扩展名如下:
操作系统平台 | MEX文件扩展名 |
HP-UX | mexhpux |
Linux | mexglx |
Macintosh | mexmac |
Solaris | mexsol |
Windows | 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为前缀,允许你创建、访问、操作和销毁mxArrays,前缀mex的程序在MATLAB的后台工作。例如mexEvalString子程序就工作在MATLAB的工作空间对字符串运算。
为了操作MATLAB的矩阵,矩阵访问和创建库提供一套子程序,这些子程序以mx前缀开头,它们的完整文档于在线参考网页上能找到。例如,mxGetPi函数从矩阵内取回虚数的指针。
虽然访问、创建矩阵的子程序允许操纵MATLAB矩阵,但有两种情况例外,IEEE程序和内存管理程序。例如,mxGetNaN返回一双精度数据,而非mxArray型。
MATLAB数据
在你开始编制MEX文件之前,必须先了解MATLAB支持的数据类型。
1.矩阵
MATLAB只用唯一的对象类型数据--MATLAB矩阵。所有的MATLAB变量,包括标量、矢量、矩阵、字符串、元胞矩阵、结构体及对象,它们都是存储在MATLAB矩阵里。对应C语言中,MATLAB矩阵应声明为mxArray型,mxArray型数据中包括了矩阵的类型、维数、相关数据等。如果是数值变量,它还包括该变量是实数还是复数的信息,如果是稀疏矩阵,它还记录下标和非零的元素个数,如果是结构体或对象,它还包括域的个数和域名。
2.数据存储
MATLAB中的数据是按列存储,与Fortran相同,之所以采用这种习惯,是缘于MATLAB最初是用Fortran语言编写的。
例如矩阵a=[‘house’; ‘floor’; ‘porch’]
a=
house
floor
porch
size(a)
ans=
3 5
数据存储为
h | f | p | o | l | o | u | o | r | s | o | c | e | r | h |
3.复数
复数在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.稀疏矩阵
稀疏矩阵的存储习惯与满置矩阵不同,除了指向实部和虚部的指针pr、pi外,还有三个参数nzmax、ir和jc:
nzmax 为一整数,它包括ir、pr的长度,如果有虚部的话,也包括pi的长度,它表示稀疏矩阵中不为零的元素的最大的个数。
ir 是一长度为nzmax的整数矩阵,它包含了pr和pi指针中相应元素的行下标。
jc是一长度为N+1的整数矩阵,它包含了元素列的信息。j的变化范围是0=<j<=N-1,jc[j]为第j列第一个非零项的
最后
以上就是甜美大碗最近收集整理的关于在MATLAB环境下访问外部函数的共享库文件的全部内容,更多相关在MATLAB环境下访问外部函数内容请搜索靠谱客的其他文章。
发表评论 取消回复