c++和matlab混合编程,C语言与MATLAB接口

  c++和matlab混合编程,C语言与MATLAB接口

  在参考文献的基础上。补充和完善。

  Matlab与C/C混合编程接口及其应用

  Matlab具有强大的数值计算和分析能力,C/C是最流行的高级编程语言。两者互补结合的混合编程在科学研究和工程实践中具有重要意义。从Matlab调用C/C代码和C/C调用M文件两个方面,深入研究了两者混合编程的原理和实现机制,给出了特定条件下混合编程的方法和步骤。实验表明,Matlab与C/C混合编程的接口和使用方法是有效和实用的。

  1导言

  Matlab是目前应用最广泛的数学软件,具有强大的数值计算、数据分析处理、系统分析、图形显示甚至符号运算等功能[1]。利用这个完整的数学平台,用户可以快速实现非常复杂的功能,大大提高工程分析计算的效率[2][3]。但相对于其他高级程序[3],Matlab程序是一个解释执行程序,不需要编译等预处理,运行速度较慢[4]。

  C/C语言是目前最流行的高级编程语言之一[5]。可以直接操作操作系统、应用程序和硬件,C/C语言明显优于其他解释性高级语言。一些大型应用软件如Matlab是用C语言开发的。

  在工程实践中,用户经常会遇到Matlab与C/C混合编程的问题,基于Matlab 6.5和VC6.0的开发环境,对Windows平台下两者的混合编程进行了深入研究,并给出了实例。

  2 Matlab调用C/C

  Matlab调用C/C主要有两种方式:使用MEX技术和调用C/C动态链接库。

  在Matlab和C/C混合编程之前,必须正确设置Matlab的编译器应用程序mex和编译器mbuild[1]:

  Matlab编译器应用程序的设置。

  Matlab编译器mbuild的设置:Mbuild -setup。

  2.1调用C/C的MEX文件

  MEX是Matlab Executable的缩写,是一种“可以在Matlab中调用的C(或Fortran)语言衍生程序”[6]。MEX文件使用起来非常方便,它的调用方式和Matlab的内置函数一模一样。只需在Matlab的命令提示符下输入MEX文件名即可。

  一个C/C MEX源程序通常由四个组件组成,前三个是必备内容,第四个根据实现的功能灵活选择:(1) #包含“MEX . h”;(2)MEX文件的入口函数,而MEX文件的导出名必须是mexFunction,MEX(3)mxArray;(4)API函数

  用简单的例子说明C/C的MEX源程序的编写和调用过程:

  #包含“mex.h”

  void timeSTwo(双y[],双x[])

  { y[0]=2.0 * x[0];}

  void mexFunction(int nlhs,mxArray * plhs[],int nrhs,const mxArray *prhs[])

  {

  双*x,* y;int mrows,ncols

  如果(nrhs!=1)mexermsgtxt(需要一个输入。);

  else if(nlhs 1)mexermsgtxt(太多输出参数);

  mrows=MX getm(prhs[0]);ncols=MX getn(prhs[0]);

  如果(!mxis double(prhs[0]) mxis complex(prhs[0]) !(mrows==1 ncols==1))

  mexErrMsgTxt(输入必须是非复数标量double。);

  plhs[0]=mxCreateDoubleMatrix(mrows,ncols,MX real);

  x=mxGetPr(prhs[0]);y=mxGetPr(plhs[0]);timestwo(y,x);}

  可以在matlab中编译,也可以直接在C环境中编译:

  1).(在matlab中)用指令mex timestwo.c编译这个文件,然后在MATLAB的命令行下调用生成的mex文件。2).(在VC2008中)像通用C一样编译后会生成dll,这样就可以直接在Matlab中使用,或者复制改变后缀。mexw32。(因为以后版本的Matlab R2010b可能不支持调用带dll后缀的mex文件)

  2.2调用C/C动态链接库(即常用的C程序dll不使用mex的接口函数)

  Matlab提供了动态链接库DLL文件的接口[7]。有了这个接口,可以在Matlab中调用动态链接库导出的函数。Matlab DLL的接口支持各种语言编写的DLL文件。在调用DLL文件之前,需要准备好函数定义的头文件。对于C/C语言开发的DLL文件,可以使用源程序中对应的头文件;对于用其他语言开发的dll,要手动准备等价的C语言函数定义头文件。

  在Matlab中使用动态链接库接口技术通常需要完成以下四个步骤:

  (1)打开动态连接库文件;(2)为调用函数准备数据;(3)调用从动态链接库文件中导出的函数;(4)关闭动态连接库文件。

  实现以上步骤,用到的Matlab函数有:loadlibrary、loadlibrary、calllib、libfunctions、lipointer、libstruct、libisloaded。下面举例说明Matlab调用C/C动态链接库的方法和步骤:

  A.在VC环境下,新建项目——win32动态连接库——项目名Test1——空项目——完成;

  B.创建新的C源文件-添加一个. cpp,内容为:#include a.h

  _ declspec(dll export)int add(int a,int b){ return a b;}

  C.新建一个-C/C头文件-add a.h,内容为:_ declspec(dll export)int add(int a,int b);然后编译生成Test1.dll动态链接库文件,将Test1.dll和A.H .复制到Matlab的工作目录下。

  D.在Matlab的命令行下调用Test.dll: LoadLibrary (test1 , a . h );x=7;

  y=8;calllib(Test1 , add ,x,y);Ans=15 unloadlibrary(Test1 )。

  调用DLL动态链接库的方法为Matlab重用工程实践中积累的大量实用C/C代码提供了一种简便的方法。与调用MEX文件相比,该方法更加简单实用。不过这个接口支持C,但是不支持C库和函数的重载。在这种情况下,建议使用MEX-file。如果真的要用这种方法(调用C/C动态连接库),就要对C做一些改动,详见3358 www.mathworks.de/help/techdoc/MATLAB _外部/f43202.html # bq。

  3/C调用Matlab

  在工程实践中,C/C调用Matlab的方法主要有调用Matlab计算引擎、包含M文件转换的C/C文件、调用M文件生成的DLL文件。

  3.1使用Matlab计算引擎

  Matlab的引擎库为用户提供了一些接口函数。通过这些接口函数,用户可以在自己的程序中以计算引擎的形式调用Matlab文件。该方法采用客户/服务器模式,使用Matlab引擎连接Matlab和C/C,在实际应用中,C/C程序是客户端,Matlab是本地服务器。

  C/C程序向Matlab计算引擎传递命令和数据信息,从Matlab计算引擎接收数据信息[2]。

  Matlab提供了以下C语言计算引擎访问函数供用户使用[8]: Engopen、engClose、engGetVariable、engPutVariable、engEvalString、engOutputBuffer、engOpenSingleUse、engGetVisible、engSetVisible。

  用下面的C语言写的,调用Matlab引擎计算方程x3?以2x=0根的源程序Example2.c为例,说明C/C调用Matlab计算引擎编程的原理和步骤:

  # include windows . h # include stdlib . h

  # include stdio . h # include engine . h

  int PASCAL WinMain(HANDLE h instance,HANDLE hPrevInstance,

  LPSTR lpszCmdLine,int nCmdShow)

  {

  发动机* epmxArray *P=NULL,* r=NULL

  充电缓冲器[301];双poly[4]={ 1,0,-2,5 };

  如果(!(ep=engOpen(NULL)))

  {fprintf( stderr, \n无法启动MATLAB引擎\ n );返回EXIT _ FAILURE}

  P=mxCreateDoubleMatrix( 1,4,MX real);mxSetClassName( P, P );

  memcpy( ( char * ) mxGetPr( P),(char *) poly,4 * sizeof(double));

  engPutVariable( ep,P);engOutputBuffer( ep,Buffer,300);

  EngEvalString( ep, disp([多项式,poly2str(p, x ),根]),r=根(p));

  Messagebox (null,buffer, example2展示MATLAB引擎的应用,MB _ OK);

  eng close(EP);mxDestroyArray(P);返回EXIT _ SUCCESS

  }

  在Matlab下运行example2.exe: mex -f example2.c。运行结果如图1所示:

  利用计算引擎调用Matlab的特点是:节省大量系统资源,应用程序整体性能较好,但无法脱离Matlab的环境运行,运行速度较慢。但对于一些特殊应用可以考虑[9](如三维图形显示)。

  3.2 MCC编译器生成的cpp和hpp文件

  Matlab自带的cc compiler-MCC可以把M文件转换成C/C代码。因此,它为C/C程序调用M文件提供了另一种方便的方法。以下是相应步骤的示例:

  A.创建一个新的example3.m:函数y=ex maple 3(n)y=0;for I=1:n y=y I;目标

  保存后,在命令窗口中输入:mcc -t -L Cpp -h example3。

  在工作目录中生成了两个文件,example3.cpp和example3.hpp。

  B.在VC中创建一个新的基于对话框的MFC应用程序Test2,添加一个按钮,并添加一个按钮响应函数。功能内容见步骤F。将上面生成的两个文件复制到VC项目的Test2目录下。

  C.在VC中选择:项目-设置,选择属性表的链接选项,在下拉菜单中选择输入,在对象/库模块中添加libmmfile、libliblibmatlb、libliblibmx、libliblibmat、libliblibmatpm、libsgl、liblibmwsglm、liblibmwservices、lib。(使用Matlab图形库时需要添加后三种。)请注意,它们是用空格隔开的。并添加msvcrt.lib在忽略库中;

  D.选择属性表C/C选项,从下拉菜单中选择General,保留预处理程序定义中的原始内容,添加MSVC、IBM PC和MSWind,用逗号分隔。从下拉菜单中选择预编译头选项,在“自动使用预补偿头”中添加stdafx.h,然后确认。

  E.选择:工具-选项,在属性页选择“目录”,添加:c:\ MATLAB 6 p5p 1 p 1 \ extern \ include,c:\ MATLAB 6 p5p 1 p 1 \ extern \ include \ CPP;然后添加:c: \ matlab6p5p1p1 \ bin \ win32,c:\ MATLAB 6 p5p 1 p 1 \ extern \ lib \ win32 \ Microsoft \ msvc 60;注意用户的Matlab安装位置,并修改相应的目录。

  F.将头文件添加到响应函数:# include MATLAB . HPP # include example 3 . HPP 该函数的响应代码为:

  int I;mwArray n;n=10n=示例3(n);I=n . extract scalar(1);

  CString字符串;str . format( example 3的返回值是:%d ,I);AfxMessageBox(str);

  G.编译、连接和执行,结果如图2所示。

  3.3 MCC编译器生成的DLL文件

  Matlab的C编译器不仅可以将Matlab的M文件转换成C/C源代码,还可以完全脱离Matlab的运行环境生成独立的可执行DLL程序。所以在C/C程序中调用DLL就可以调用Matlab代码。下面用一个简单的例子来说明C/C调用M文件生成的DLL:

  A.创建m文件example4.m:函数结果=example4 (para)

  x=[1第3段];y=[1 3 1];plot( x,y);结果=para * 2;结束。然后在命令窗口中输入:

  MCC-t-w libhg:example4-t link:Li b-h libmmfile . mlib libmwsglm . mlib example 4生成三个文件,example 4。dll,示例4。11b和例4。在工作目录中。

  B.在VC中创建新的基于对话框的应用程序Test3,然后添加一个按钮和按钮响应函数。函数内容见步骤D,然后将生成的三个文件复制到Test2项目目录下。

  C.VC编译环境的设置如3.2节步骤c和d;

  D.将以下头文件添加到按钮函数文件中:#include example4。h ,函数响应代码为:

  mxArray * para=mxCreateDoubleScalar(2);mxArray*结果;example 4 initialize();

  result=mlfexample 4(para);CString字符串;

  海峡。Format( %f ,mxGetScalar(result));AfxMessageBox(str);

  E.编译、连接和执行,结果如图3所示。

  mcc编译器生成的DLL动态链接库文件只需要包含在C/C编译环境中,通过调用export函数就可以实现原M文件的功能,极大地方便了用户的代码设计。

  4结束语

  本文从Matlab调用C/C代码和C/C调用M文件两个方面详细研究了Matlab和C/C的混合编程技术。对于Matlab调用C/C代码,给出了常用的MEX技术和调用C/C动态链接库的方法,并进行了比较。针对用户在实际中C/C调用Matlab时经常遇到的问题,通过研究给出了三种常见的方法及其特点:使用Matlab计算引擎的方法,混合编程后的可执行程序无法脱离Matlab的运行环境,运行速度很慢;使用mcc编译器将M文件转换成C/C文件的方法,虽然可以独立于Matlab运行环境,但是可以将生成的文件包含在C/C环境中,非常复杂;而M文件生成的DLL给用户提供了一个简单方便的C/C调用Matlab代码的方法。除了Matlab自带的mcc,Matcom还可以把M文件编译成C/C文件和DLL文件[2][8],不过混合编程的原理是一样的,这里就省略了。

  MATLAB混合C/C编程调用C程序。

  12073人阅读评论(13)收集报道

  耗时的函数可以用C语言实现,编译成mex函数来加速执行。Matlab本身没有C语言的编译器,所以要求你的机器上已经安装了VC,BC或者WatcomC中的一个。如果你在安装Matlab的时候已经设置了编译器,现在应该可以用mex命令来编译C语言的程序了。如果当时没选,在Matlab中输入mex-setup。按照下面的提示一步一步设置就可以了。请注意,早期版本的在设置编译器路径时只能使用8个字符形式的路径名。比如我用的VC安装在路径C:/PROGRAMFILES/DEVSTUDIO,那么设置路径时应该写成:“C:/PROGRA~1”。在此设置之后,可以执行mex。要测试您的路径设置是否正确,请将下面的程序另存为hello.c

  /*hello.c*/

  #包含“mex.h”

  voidmexFunction(intnlhs,mxArray*plhs[],intnrhs,constmxArray*prhs[])

  {mexPrintf(你好,世界!/n’);

  }

  假设你把hello.c放在C:/TEST/下,在Matlab中用CDC:/TEST/把当前目录改成C:/TEST/(注意,只是把C:/TEST/加到搜索路径上是没有用的)。现在敲门:

  墨西哥城

  如果一切顺利,编译应该会在编译器提示消息出现后正常退出。如果您添加了C:/TEST/

  输入搜索路径,现在键入hello,程序将在屏幕上键入一行:

  你好,世界!

  在C/TEST/目录中查找,您将找到另一个文件:HELLO.DLL。这样,第一个mex函数就完成了。分析hello.c,可以看到程序的结构非常简单,整个程序由一个接口子进程mexFunction组成。

  voidmexFunction(intnlhs,mxArray*plhs[],intnrhs,constmxArray*prhs[])

  如前所述,Matlab的mex函数有一定的接口规范,这意味着

  Nlhs:输出参数数量

  Plhs:输出参数的指针

  Nrhs:输入参数数量

  例如,使用

  [a,b]=测试(c,d,e)

  当调用mex函数测试时,传递给test的四个参数是

  2,plhs,3,prhs

  其中包括:

  prhs[0]=c

  prhs[1]=d

  prhs[2]=e

  当函数返回时,它会将你在plhs[0]和plhs[1]中的地址分配给A和B以返回数据。

  请注意,您可能已经注意到prhs[i]和plhs[i]是指向mxArray类型数据的指针。这种类型是在mex.h中定义的,其实Matlab中的大部分数据都是以这种类型存在的。当然,还有其他数据类型。请参考Apiguide.pdf的介绍。

  为了让大家更直观的了解参数传递的过程,我们重写hello.c,使其可以基于输入

  输入参数的改变给出了不同的屏幕输出:

  //hello.c2.0

  #包含“mex.h”

  voidmexFunction(intnlhs,mxArray*plhs[],intnrhs,constmxArray*prhs[])

  {

  inti

  I=mxGetScalar(prhs[0]);

  如果(i==1)

  MEX printf(‘你好,世界!/n’);

  其他

  MexPrintf(大家好!/n’);

  }

  编译完这个程序后,执行hello(1),屏幕将键入:

  你好,世界!

  而hello(0)会得到:

  大家好!

  现在,程序hello可以根据输入的参数给出相应的屏幕输出。在这个程序中,除了屏幕输出函数mexPrintf(用法与C中的Printf函数几乎完全相同)之外,还使用了一个函数:mxGetScalar,调用如下:

  I=mxGetScalar(prhs[0]);

  “标量”是指标量。在Matlab中,数据以数组的形式存在。mxGetScalar的作用是将通过prhs[0]传递的mxArray类型的指针所指向的数据(标量)赋给C程序中的变量。这个变量应该是double类型的,它通过强制类型转换被赋给整形变量I。既然有标量,显然也应该有向量,否则矩阵无法传递。请看下面的程序:

  //hello.c2.1

  #包含“mex.h”

  voidmexFunction(intnlhs,mxArray*plhs[],

  intnrhs,constmxArray*prhs[])

  {

  int * I;

  I=mxGetPr(prhs[0]);

  if(i[0]==1)

  MEX printf(‘你好,世界!/n’);

  其他

  MexPrintf(大家好!/n’);

  }

  这样通过mxGetPr函数从指向mxArray类型数据的prhs[0]中获得指向double类型的指针。

  但是,还有一个问题。如果输入的不是单个数据,而是向量或矩阵,该怎么办?我们只能通过mxGetPr得到这个矩阵的指针。如果我们不知道这个矩阵的确切大小,我们会

  无法计算。

  为了解决这个问题,Matlab提供了mxGetM和mxGetN两个函数来获取传入参数的行数和列数。下面这个例程的功能很简单,就是获取输入矩阵并显示在屏幕上:

  //show.c1.0

  #包含“mex.h”

  voidmexFunction(intnlhs,mxArray*plhs[],intnrhs,constmxArray*prhs[])

  {

  双*数据;

  intM,N;

  inti,j;

  data=mxGetPr(prhs[0]);//获取指向矩阵的指针

  m=MX getm(prhs[0]);//获取矩阵中的行数

  n=MX getn(prhs[0]);//获取矩阵的列数

  for(I=0;我我)

  { for(j=0;j j)

  mexPrintf(%4.3f ,data[j * M I]);

  MEX printf(/n );

  }

  }

  编译后,用以下命令测试它:

  a=1:10;

  b=[a;a1];

  显示(a)

  显示(b)

  需要注意的是,在Matlab中,矩阵的第一行从1开始,而在C语言中,第一行的序数是零。Matlab中的矩阵元素b(i,j)传递给c中的一维数组大数据后对应的是数据[j*M i]。

  在调用函数之前,输入数据已经被应用到Matlab的内存中。因为mex函数与Matlab共享同一个地址空间,所以可以通过传递prhs[]中的指针来达到参数传递的目的。但是输出参数需要在mex函数中申请内存空间,这样指针才能放在plhs[]中并传递出去。由于返回指针类型必须是mxArray,Matlab特别提供了一个函数:mxCreateDoubleMatrix来实现内存的应用。该函数的原型如下:

  mxArray * mxCreateDoubleMatrix(intm,intn,mxComplexityComplexFlag)

  m:要应用的矩阵的行数

  n:要应用的矩阵的列数

  在为矩阵申请内存后,你得到一个mxArray类型的指针,可以放在plhs[]中并传递回来。但是,这个新矩阵的处理必须在函数内部完成,所以我们需要使用前面介绍的mxGetPr。使用mxGetPr得到指向这个矩阵中数据区的指针(double type)后,就可以对这个矩阵进行各种操作和运算了。下面的程序是在上面show.c的基础上稍加改动,功能就是输。

  //reverse.c1.0

  #包含“mex.h”

  voidmexFunction(intnlhs,mxArray*plhs[],

  intnrhs,constmxArray*prhs[])

  {

  double * inData

  double * outData

  intM,N;

  inti,j;

  in data=mxGetPr(prhs[0]);

  m=MX getm(prhs[0]);

  n=MX getn(prhs[0]);

  plhs[0]=mxCreateDoubleMatrix(M,N,MX real);

  out data=mxGetPr(plhs[0]);

  for(I=0;我我)

  for(j=0;j j)

  out data[j * M I]=in data[(N-1-j)* M I];

  }

  当然Matlab使用的矩阵不仅仅是double,还有字符串型、稀疏型、结构型矩阵等等,并提供了相应的处理函数。在本文中,我们使用了一些在mex编程中最常遇到的函数,其余的细节请参考Apiref.pdf。

  通过前两部分的介绍,我们应该对参数的输入输出方法有一个基本的了解。有了这些知识,你就可以满足一般的编程需求了。但是,这些程序仍然有一些小缺陷。前面介绍的re容错性差是因为前面的程序没有检查输入输出参数的数量和类型,而后面的程序容错性更好。

  #包含“mex.h”

  voidmexFunction(intnlhs,mxArray*plhs[],intnrhs,constmxArray*prhs[])

  {

  double * inData

  double * outData

  intM,N;

  //异常处理

  //异常处理

  如果(nrhs!=1)

  mexErrMsgTxt(用法:b=reverse(a)/n );

  如果(!mxIsDouble(prhs[0]))

  mexermsgtxt( theInputMatrixmustbedouble!/n’);

  in data=mxGetPr(prhs[0]);

  m=MX getm(prhs[0]);

  n=MX getn(prhs[0]);

  plhs[0]=mxCreateDoubleMatrix(M,N,MX real);

  out data=mxGetPr(plhs[0]);

  for(I=0;我我)

  for(j=0;j j)

  out data[j * M I]=in data[(N-1-j)* M I];

  }

  在上面的异常处理中,使用了两个新的函数:mexErrMsgTxt和mxIsDouble。MexErrMsgTxt给出错误提示并退出当前程序。MxIsDouble用于确定mxArray中的数据是否是Double。当然,Matlab也提供了很多判断其他数据类型的函数,这里就不赘述了。

  需要注意的是,在Matlab提供的API中,有两个函数前缀:mex-和mx-。带有mx- prefix的函数大多是对mxArray数据进行操作的函数,如MxISDOUBLE、MxCreateDoubleMatrix等。而那些带有mex前缀的多为与Matlab环境交互的函数,如mexPrintf、mxErrMsgTxt等。了解这一点有助于在Apiref.pdf找到所需的功能。

  至此,介绍了用C写mex函数的基本过程。

  出发地:http://blog.csdn.net/jtop0/article/details/7657227

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

相关文章阅读

  • matlab点乘和数乘,matlab中矩阵的乘法和点乘、点除
  • gabor滤波器matlab代码,gabor滤波器 提取特征
  • ,,matlab画三维图像的示例代码(附demo)
  • ,,matlab灰度图像调整及imadjust函数的用法详解
  • ,,Matlab中plot基本用法的具体使用
  • gabor滤波器matlab代码,gabor滤波器 提取特征,python Gabor滤波器讲解
  • matlab gui程序设计,matlab gui设计入门与实战
  • matlab roc曲线,matlab绘制ROC曲线
  • matlab画图标注数据,matlab 图标注
  • 模式识别matlab应用实例,模式识别matlab实现
  • matlab linspace(x,y,length(Y)),Python中linspace函数
  • matlab NaN函数,matlab中nargin的用法示例
  • MATLABR2018a,matlab2018a使用方法
  • 图像处理用python还是matlab,matlab灰度处理
  • python 模糊聚类,聚类分析matlab编程
  • 留言与评论(共有 条评论)
       
    验证码: