Matab与C混合编程 C_MEX函数编写

来源:互联网 发布:淘宝818会有活动吗 编辑:程序博客网 时间:2024/06/02 02:59

1、为什么我们要用C_MEX 文件

   我们知道Matlab擅长处理矩阵运算,提供了很多内建函数以及工具箱,但是对于大量循环的处理效率较低,会出现计算速度的瓶颈,而C对于循环有着高效的处理方式。结合两者特性,我们尝试将耗时的部分改用C实现,由Matalb进行调用。通过使用mex文件,使得Matlab调用C程序与调用内置函数一样简单。

2.、mex文件的组成

C语言MEX 函数主要由计算子程序和接口子程序两个部分组成。

>CMatlab之间的接口函数(由mexFunction实现)

>用C编写的实现特定功能的计算程序(由用户编写完成特定的功能)

>与平台相关的预处理宏(Windows平台下与C相关的宏,主要与mxArray类相关)

注: 将C/Cpp 文件编译为matlab可以执行的程序,关键是“数据格式的转换”。Matlab中使用的是矩阵类型,一个标量也是使用矩阵进行表述的;而C/CPP中使用的初级类型是int,double等。如何将两类数据调整一致是一个基本问题。

   mex文件入口函数:void mexFunction(int nlhs,mxArray *plhs[], int nrhs,const mxArray *prhs[]);

mexFunction四个参数的意思为:

nlhs= 1,说明调用语句左手面(lhs-lefthand side)有一个变量,即a。

nrhs= 2,说明调用语句右手面(rhs-righthand side)有两个自变量,即b和c。

plhs是一个数组,其内容为指针,该指针指向数据类型mxArray。因为现在左手面只有一个变量,即该数组只有一个指针,plhs[0]指向的结果会赋值给a。

prhs和plhs类似,因为右手面有两个自变量,即该数组有两个指针,prhs[0]指向了b,prhs[1]指向了c。要注意prhs是const的指针数组,即不能改变其指向内容。

注:因为Matlab最基本的单元为array,无论是什么类型也好,如有double array、 cell array、 struct array……所以a,b,c都是array,b= 1.1便是一个1x1的doublearray。而在C语言中,Matlab的array使用mxArray类型来表示。所以就不难明白为什么plhs和prhs都是指向mxArray类型的指针数组。


接下来是在mex文件中实现函数功能,mex文件名就是被Matlab调用的文件名,在C/C++文件中对定义功能,并且接口的数据结构严格依照Matlab的规定,传入传出参数都是mxArray。
(i)先将传入的mxArray参数,利用Matlab提供的API函数转成C/C++数据,如 int mrow = mxGetM(mxArray* p) , double* p = mxGetPr(prhs[0]).
(ii)在mexFunction中调用C/C++function ,得到C/C++中类型数据。
(ii)将得到的C/C++数据转成mxArray数据结构传出。
mex编译器负责将这样的“八股文”翻译成为matlab可以执行的二进制文件。

3、mex文件的编写、编译、运行

注:同一目录下如果有m函数文件和编译生成的mex64库文件,Matlab优先调用库文件函数。
这里我们实现两个双精度数相加,matlab m文件对应函数如下 :
function [ z ] =  mexAdd( x,y )%UNTITLED Summary of this function goes here%   Detailed explanation goes here    disp('this is a function.');    z = x+y;end

现在,我们要用C的方式来实现:
mexAdd.c文件如下:
//包含头文件#include "mex.h"//C 函数double mexAdd(double x,double y){    return x+y;}//MEX文件的入口函数mexFunctionvoid mexFunction(int nlhs,mxArray *plhs[], int nrhs,const mxArray *prhs[]){    double a;    double b;    double *c;    //输入参数、输出参数判断    if(nlhs != 1){        mexErrMsgTxt("One output required!");    }    if(nrhs != 2){        mexErrMsgTxt("Two input required!");    }    //传入的mxArray参数,利用Matlab提供的API函数转成C/C++数据    a = *( mxGetPr(prhs[0]) );    b = *( mxGetPr(prhs[1]) );        plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL);    c = mxGetPr(plhs[0]);    *c = mexAdd(a,b);}
对于没有配置编译Cmex的首先需要选择配置编译器,如下:
有些matlab 自带有Lcc编译器,只是用lcc编译时不支持汉语注释吗,只能用英语注释。。。



然后就是使用mex命令编译C文件了,编译成功后生成对应的  .mexw64文件或者.mexw32文件,调用时跟普通内建函数使用无区别。


4、数组相加实例

# include "mex.h"void mexArrayAdd(const int Row,const int Col,const double *A,const double *B,double *C){    int i,j;    for(i=0;i<Row;i++){        for(j=0;j<Col;j++){            //注意数据的表达方式, C语言是按行存储A[i*Col+j],matlab是按列存储 A[i+j*Row]            C[i+j*Row] = A[i+j*Row] + B[i+j*Row];         }    }}void mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[]){    double *A,*B,*C;    int RowA,ColA,RowB,ColB;    if(nlhs != 1){       mexErrMsgTxt("One output required.");    }    else if(nrhs > 2){        mexErrMsgTxt("Two input required.");    }    if( !mxIsDouble(prhs[0]) || !mxIsDouble(prhs[1]) || mxIsComplex(prhs[0]) || mxIsComplex(prhs[1]) ){        mexErrMsgTxt("Input Array must be double.");    }    //获得矩阵的行数    RowA = mxGetM(prhs[0]);    //获得矩阵的列数    ColA = mxGetN(prhs[0]);    RowB = mxGetM(prhs[1]);    ColB=  mxGetN(prhs[1]);    //判断行列是否相等    if(RowA != RowB || ColA != ColB){        mexErrMsgTxt("Rows and Cols must be same.");    }    //获取指向输入参数的指针    A = mxGetPr(prhs[0]);    B = mxGetPr(prhs[1]);    //生成输出参量的mxArray    plhs[0] = mxCreateDoubleMatrix(RowA,ColB,mxREAL);    //获取指向输出参数的指针    C= mxGetPr(plhs[0]);    mexArrayAdd(RowA, ColA, A, B, C);}




原创粉丝点击