很多精通单一语言,c语言或matlab的人,在处理经常遇到Matlab与C/C++混合编程的问题,而且都会出现各种编译问题,使得这两种语言之间产生了代沟,因为我对这些问题也比较反感,因此做一个简单认识和学习。
一、Matlab调用C/C++
Matlab调用C/C++的方式主要有两种:利用MEX技术和调用C/C++动态连接库。
利用MEX技术:
MEX是Matlab Executable的缩写。一个C/C++的MEX源程序通常包括4个组成部分,其中前3个是必须包含的内容,第4个则根据所实现的功能灵活选用:(1)#include “mex.h”;(2)MEX文件的入口函数mexFunction, MEX文件导出名必须为mexFunction函数;(3)mxArray;(4)API函数
mexFunction函数中的四个参数说明:
nlhs:mexFunction的第一个参数,它指示Matlab的调用命令中等号左侧有几个变量。
plhs: mexFunction的第二个参数,它指示Matlab的调用命令中等号左侧变量的指针。
nrhs:mexFunction的第三个参数,它指示Matlab的调用命令中等号右侧的变量个数。
prhs:mexFunction的第四个参数,它指示Matlab调用命令中等号右侧的变量指针。
通过简单的例子说明C/C++的MEX源程序编写和调用过程:
#include "mex.h" /* * timestwo.c - example found in API guide * * Computational function that takes a scalar and doubles it. * * This is a MEX-file for MATLAB. * Copyright (c) 1984-1998 The MathWorks, Inc. */ /* $Revision: 1.5 $ */ /* 本MEX文件的目的是实现timestwo的功能 void timestwo(double y[], double x[])是你的C++函数 */ void timestwo(double y[], double x[]) { y[0] = 2.0*x[0]; } /*下面这个mexFunction的目的是使MATLAB知道如何调用这个timestwo函数*/ void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] ) /* nlhs是MATLAB命令行方式下输出参数的个数; *plhs[]是MATLAB命令行方式下的输出参数; nrhs是MATLAB命令行方式下输入参数的个数; *prhs[]是MATLAB命令行方式下的输入参数; */ { double *x,*y; int mrows,ncols; /* Check for proper number of arguments. */ if(nrhs!=1) { mexErrMsgTxt("One input required."); } else if(nlhs>1) { mexErrMsgTxt("Too many output arguments"); } /* 在MATLAB命令行方式下,本MEX文件的调用格式是y=timestwo(x) 输入参数(x)个数=1,输出参数(y)个数=1,所以在程序一 开始就检查nrhs是否=1以及nlhs是否>1(因为MATLAB有一个缺省 输出参数ans,所以nlhs可以=0 */ 输出参数ans,所以nlhs可以=0 */ /* The input must be a noncomplex scalar double.*/ mrows = mxGetM(prhs[0]); /* 获得输入矩阵的行数 */ ncols = mxGetN(prhs[0]); /* 获得输入矩阵的列数 */ if( !mxIsDouble(prhs[0]) || mxIsComplex(prhs[0]) || !(mrows==1 && ncols==1) ) { mexErrMsgTxt("Input must be a noncomplex scalar double."); } /* 判断输入矩阵是否是double类,以及它是否只包括单个元素 */ /* 为输出创佳一个矩阵,显然这个矩阵也应该是1x1的 */ plhs[0] = mxCreateDoubleMatrix(mrows,ncols, mxREAL); /* 获得指向输入/输出矩阵数据的指针 */ x = mxGetPr(prhs[0]); y = mxGetPr(plhs[0]); /* 调用C++函数timestwo(y,x) */ timestwo(y,x); }
1).(在matlab中)用指令mex timestwo.c编译此文件,然后在MATLAB命令行下调用生成的MEX文件即可。2). (在VS2013中)和一般c++一样编译后,就会产生dll,这样可以直接在Matlab中用了,或者copy且更改后缀名.mexw32即可。
MEX文件的编程规则
(1)编制自己的C++算法程序
(2)紧跟着定义mexFunction函数,mexFunction的定义法唯一:
它只能是如下形式:
void mexFunction( int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[] )
其名称和参数类型不许有任何改变,在mexFunciton函数中可以调用你刚定义好的C++程序。
MEX文件的编译
MATLAB提供了专门编译MEX文件的工具:mex,它可以把你做好的C++源程序编译成 .mex文件供MATLAB在命令行方式下调用。调用时输入你的C++函数名(上例中为timestwo)。具体mex的设置和使用方法可以在MATLAB命令行方式下用help mex命令获得。
调用C/C++动态连接库(即:一般普通的C程序dll没有用mex的接口函数)
Matlab提供对动态连接库DLL文件的接口。利用该接口,可在Matlab中调用动态连接库导出的函数。Matlab对DLL的接口支持各种语言编写的DLL文件。在调用DLL文件之前,需要准备函数定义的头文件。对于C/C++语言开发的DLL文件,可使用源程序中相应的头文件;而对于其他语言开发的DLL,则要手工准备等效的C语言函数定义头文件。
在Matlab中利用动态连接库接口技术通常需要完成以下4个步骤:
(1)打开动态连接库文件;(2)为调用函数准备数据;(3)调用动态连接库文件中导出的函数;(4)关闭动态连接库文件。
为了实现以上步骤,用到的Matlab函数有:loadlibrary, loadlibrary, calllib, libfunctions, lipointer, libstruct, libisloaded。
下面举例说明Matlab调用C/C++动态连接库的方法和步骤:
a.在VS环境下,新建工程->win32动态连接库->工程名Test->empty工程->完成;
b.新建->C++源文件->添加a.cpp,内容为:#include "a.h"
_declspec(dllexport) int add(int a, int b) { return a+b; }
c.新建->C/C++头文件->添加a.h,内容为: _declspec(dllexport) int add(int a,intb); 然后编译生成Test.dll动态连接库文件,将Test.dll和a.h拷到Matlab 工作目录下。
d.在Matlab命令行下,调用Test.dll:>>loadlibrary(‘Test’,’a.h’); >>x=7;
>>y=8; >>calllib(‘Test’,‘add’,x,y); Ans=15 >>unloadlibrary(‘Test’).
调用DLL动态连接库的方法,为Matlab重用工程实践中积累的大量实用C/C++代码提供了一种简洁方便的方法。与调用MEX文件相比,该方法更加简便实用。(C++库和函数的重载不知道怎么实现)
二、C/C++调用Matlab
1、设置matlab编译器
在命令行窗口下,输入并执行如下命令:mex –setup
在出现的编译器中,选择VS2013
然后在输入命令:mbuild –setup 同样选择VS2013
2. 编写.m文件
如下函数时完成图像的分割功能,第一个参数是图像的文件名(路径),第二个参数是分割图像阈值的大小;完成分割后,将图像保存为result.bmp;返回值则是原图像的数据;
function imagedata=improcess(filename,threshold); imagedata=double(imread(filename)); newbuf=imagedata; [M N]=size(imagedata); for i=1:1:M for j=1:1:N if imagedata(i,j)>threshold newbuf(i,j)=255; else newbuf(i,j)=0; end end end imwrite(uint8(newbuf),'result.bmp'); return;
3、编译.m文件
mcc -W cpplib:MatImprocess -T link:lib improcess
解释:其中-W是控制编译之后的封装格式;
cpplib,是指编译成C++的lib;
cpplib冒号后面是指编译的库的名字;
-T表示目标,link:lib表示要连接到一个库文件的目标,目标的名字即是.m函数的名字。
编译完成之后,MatImprocess.h MatImprocess.lib MatImprocess.dll这三个文件时我们在c++中调用所需要的;这三个文件和我们用c++编写dll时,生成的三个文件时对应的;
但是由于我的matlab是2014b,破解不是很完美,所以这个自带mcc编译器运行不起来,后面暂时做不了了,先隔一段时间再弄一下了,如果哪位热心的朋友能够在matlab2014b下面完美破解mcc,运行的起来,通知我一下,谢谢。