我是靠谱客的博主 甜美大碗,这篇文章主要介绍在MATLAB环境下访问外部函数的共享库文件,现在分享给大家,希望可以做个参考。

在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环境下访问外部函数内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(63)

评论列表共有 0 条评论

立即
投稿
返回
顶部