原作者,胡荣春 2006-10-11

MEX文件简介

在MATLAB中可调用的C或Fortran语言程序称为MEX文件。MATLAB可以直接把MEX文件视为它的内建函数进行调用。MEX文件是动态链接的子例程,MATLAB解释器可以自动载入并执行它。

MEX文件主要有以下用途:

1.  对于大量现有的C或者Fortran程序可以无须改写成MATLAB专用的M文件格式而在MATLAB中执行。

2.  对于那些MATLAB运算速度过慢的算法,可以用C或者Frotran语言编写以提高效率。

例子

为格式详解做准备。下为实例1。

#include "mex.h"

/*    timestwo.c   本MEX文件的目的是实现times two的功能*/

void timestwo(double y[], double x[])

{

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

}

/*下面这个mexFunction的目的是使MATLAB知道如何调用这个timestwo函数

nlhs是MATLAB命令行方式下输出参数的个数;

*plhs[]是MATLAB命令行方式下的输出参数;

nrhs是MATLAB命令行方式下输入参数的个数;

*prhs[]是MATLAB命令行方式下的输入参数; */

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

{

double *x,*y; //double指针类型不能改变!!

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 */

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]);

timestwo(y,x); /* 调用C 函数timestwo(y,x) */

}

把上面这个文件timestwo.c编辑完成后,在matlab命令行里输入:

mex timestwo.c

matlab会提示你选择一个编译器进行编译,如果安装了VC,则选择VC++即可。编译完成后会在同一目录下生成同名的动态链接库文件timestwo.dll。此后再输入“mex ***.c”编译mex文件时将不再提示用户选择编译器,而自动选择默认的编译器编译。若想改变编译器进行编译,可输入“mex timestwo.c –setup”。

编译完成后即可使用此动态链接库了。在MATLAB命令行下输入:

x = 2;

y = timestwo(x)

将会显示:

y =

MEX文件格式详解

首先编制自己的C算法程序,紧跟着定义mexFunction函数,mexFunction的定义法唯一,它只能是如下形式:

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

其名称和参数类型不许有任何改变,在mexFunciton函数中可以调用你刚定义好的C 程序。

3.1 参数定义

以上面的timestwo.c文件为例,当编译完成后在matlab命令行输入“y = timestwo(x)”时,matlab便随即加载timestwo.dll动态链接库文件。timestwo.dll(mexw32、mexw64)加载完成后首先执行mexFunciton函数,并把输入参数x的值“2”传递给prhs[0],输入参数的个数“1”传递给plhs。由于matlab里的变量都是以double类型存储的,故mex程序里所有输入输出参数对应的C类型均应为double。这也是为什么上例中定义“double *x,*y;”必须为double指针类型的原因。而且还要注意,必须是double指针,不能仅为double

3.2  输入输出参数检查

接下来可以做输入参数的检查,确定输入参数的个数是否符合定义,否则给出错误提示信息。

3.3 参数挂接

参数检查完成以后就是对应输入输出参数的挂接(一时想不到更好的词,此处暂借用“挂接”一词表达如下所述的意思):

/* 为输出创建一个矩阵,显然这个矩阵也应该是1x1的 */

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

x = mxGetPr(prhs[0]); /* 获得指向输入/输出矩阵数据的指针 */

y = mxGetPr(plhs[0]);

这里首先给输出参数创建了一个矩阵。注意,不论输出的是一个矩阵还是一个标量,都必须为所有的输出参数创建单独的矩阵。如果是标量,则创建的时候把行和列都设为1即可:

mxCreateDoubleMatrix(1,1, mxREAL);

之所以这样做的原因是matlab里面每个变量都是以矩阵形式存在的。

prhs[]和plhs[]是不能直接在程序中使用的,必须要定义对应的指针变量。故而要对接口参数的指针和程序中使用参数的指针进行挂接,也就是“x = mxGetPr(prhs[0]);”语句所做的工作。看到这里就应该明白为什么void mexFunction函数里面所有的输入输出参数都必须定义为double指针的原因了吧。因为所有定义的参数必须要和prhs[]、plhs[]进行挂接。

3.4  调用功能函数

参数挂接完成以后就可以调用自己编写的功能函数了:

timestwo(y,x); /* 调用C 函数timestwo(y,x) */

这里需要注意,调用的输入参数与定义的参数要相符。如timestwo()函数的定义如下:

void timestwo(double y[], double x[])

两个参数均为指针类型,故调用的时候“timestwo(y,x);”输入的是“y,x”两个指针。而如果timestwo()函数的定义为:

void timestwo(double y[], double x)

则说明输入参数x应该为double类型的变量,这时的输入参数可写为:

timestwo(y,x[0]);

3.5  功能函数的编写

功能函数的编写取决于用户要完成的功能。这里值得提出来说明的有以下2点:

(1)   功能函数名和最终在matlab里调用的函数名没有直接联系,而只于mexFunction里调用的函数名有关系。Matlab调用的函数名取决于最后生成的dll文件名,而这个文件名可以任意更改(但首字母不能为数字)。

(2)   功能函数没有返回值,是void类型,而整个dll模块最终返回给matlab的输出参数是包含在功能函数的输入参数中的。由前面介绍的输入输出参数需要挂接的原因,故功能函数的输入参数中对应的最终输出参数必须定义为double指针类型,如:“void timestwo(double y[], double x)”。其中y是最终的输出参数,必须为double指针类型,而从matlab里传来的输入参数,则视情况而定是否需要定义为指针类型。

3.6   实例2

这个例子是完成dijkstra最短路径算法的程序。

#include "mex.h"

/* 求网络中所有节点到指定节点的最短路,Dijkstra算法*/

#define INFN    1000

#define INFI    10000

void f_dijkstra_all(double *w, double *D, unsigned long n, unsigned long p)

{

unsigned long i,j,wtmp,pnew,nu=n-1,np=1;//np为已知距离节点数,nu为未知距离节点数,IDp为已知节点ID

unsigned long IDu[INFN], IDp[INFN];       //未知节点IDu, 已知节点IDp

p--;

IDp[0]=p;

for (i=0;i<n;i++)

{

w[i]=D[n*i+p];

if ( i<p )

IDu[i]=i;

else

IDu[i]=i+1;

}

while (nu)

{   wtmp=INFI;

for (i=0;i<nu;i++)

{   for (j=0;j<np;j++)

if ( w[IDp[j]]+D[ n*IDp[j]+IDu[i] ] < w[IDu[i]] )

w[IDu[i]]=w[IDp[j]]+D[ n*IDp[j]+IDu[i] ];

if ( w[IDu[i]]<INFI && w[IDu[i]] < wtmp )

{   wtmp=w[IDu[i]];

pnew=i;

}

}

if ( wtmp<INFI )

{   IDp[j]=IDu[pnew];

np++;

for (i=0;i<nu;i++)               //IDu(pnew)=[];

if ( i>=pnew )

IDu[i]=IDu[i+1];

nu--;

}

else

nu=0;

}

}

/*下面这个mexFunction的目的是使MATLAB知道如何调用这个函数*/

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

{

  if(nrhs!=3)

mexErrMsgTxt("Three input required.");

  else if(nlhs>1)

mexErrMsgTxt("Too many output arguments");

  //mrows = mxGetM(prhs[0]);                /* 获得输入矩阵的行数 */

  ncols = mxGetN(prhs[0]);                 /* 获得输入矩阵的列数 */

  if ( mxIsComplex(prhs[0]) )

mexErrMsgTxt("Input must be a noncomplex.");      /*判断输入矩阵是否为复数*/

  plhs[0] = mxCreateDoubleMatrix(1,ncols, mxREAL);      /* 为输出创建一个矩阵*/

  D = mxGetPr(prhs[0]);                                       /* 获得指向输入/输出矩阵数据的指针 */

  n = mxGetPr(prhs[1]);

  p = mxGetPr(prhs[2]);

  w = mxGetPr(plhs[0]);

  f_dijkstra_all(w, D, n[0], p[0]);                          /* 调用C 函数*/

}

补充说明

在编写功能函数时,需要特别注意得是:matlab中的矩阵传递到C中变成数组时,元素的排列顺序是先列后行!

举个例子:把某个矩阵D作为输入参数,此矩阵为:

D=[  1   2     3

    4   5     6]

而把此输入参数挂载到某个定义好的double指针变量Dp后,依次写出Dp所指向的元素,你会发现:

Dp[0]=1

Dp[1]=4

Dp[2]=2

Dp[3]=5

Dp[4]=3

Dp[5]=6

所以要正确无误的引用原来矩阵中第i行第j列的元素,应使用Dp[i-1+(j-1)*n]。其中n为矩阵的行数。

参考文献

MATLAB与C 的接口问题分类:我的技术我做主, 北京理工大学BBS

[转载] C-MEX程序编写的更多相关文章

  1. MEX文件编写和调试

    作者kaien,2010/02/16 以前我写过一篇文章,详细的介绍过MEX的格式,语法,编译,调试等.可惜记不清放在哪里了.而最近又用到MEX编程,所以只能重新温习一番.时间有限,只记下简要流程和注 ...

  2. MEX程序中的mexFunction函数【转】

    与C中的main函数一样,MEX程序中的开始函数为mexFunction.默认变量参数是: void mexFunction(int nlhs, mxArray *plhs[], int nrhs, ...

  3. 20151009 C# 第一篇 程序编写规范

    20151009 程序编写规范 1. 代码书写规则: 1).尽量使用接口,然后使用类实现接口. 2).关键语句写注释 3).避免写超过5个参数的方法,如果要传递多个参数,则使用结构 4).避免代码量过 ...

  4. 基于DCMTK的DICOM相关程序编写攻略

    2008年09月10日 星期三 15:35 基于DCMTK的DICOM相关程序编写攻略 前言: 由于现在的医学影像设备的图像存储和传输正在逐渐向DICOM标准靠拢,在我们进行医学图像处理的过程中,经常 ...

  5. Android Camera 相机程序编写

    Android Camera 相机程序编写 要自己写一个相机应用直接使用相机硬件,首先应用需要一个权限设置,在AndroidManifest.xml中加上使用设备相机的权限: <uses-per ...

  6. HTML5 canvas绘制雪花飘落动画(需求分析、知识点、程序编写分布详解)

    看到网上很多展示html5雪花飞动的效果,确实非常引人入胜,我相信大家也跟我一样看着心动的同时,也很好奇,想研究下代码如何实现:虽然哦很多地方也能下载这些源码,不过也不知道别人制作此类动画时的思路及难 ...

  7. 从mina中学习超时程序编写

    从mina中学习超时程序编写 在很多情况下,程序需要使用计时器定,在指定的时间内检查连接过期.例如,要实现一个mqtt服务,为了保证QOS,在服务端发送消息后,需要等待客户端的ack,确保客户端接收到 ...

  8. 基于Asterisk的VoIP开发指南——(2)Asterisk AGI程序编写指南

    原文:基于Asterisk的VoIP开发指南--(2)Asterisk AGI程序编写指南 5. Asterisk AGI程序编写指南 5.1概述 很多时候,我们需要在拨号方案中做某些业务逻辑的判断或 ...

  9. .NET 开源了,Visual Studio 开始支持 Android 和 iOS 程序编写并自带 Android 模拟器

    .NET 开源了,Visual Studio 开始支持 Android 和 iOS 程序编写并自带 Android 模拟器 北京时间今天凌晨的 Connect(); 大会上,多少程序员的假想成为现实. ...

随机推荐

  1. Es官方文档整理-2.分片内部原理

    Es官方文档整理-2.分片内部原理 1.集群      一个运行的Elasticsearch实例被称为一个节点,而集群是有一个或多个拥有相同claster.name配置的节点组成,他们共同承担数据和负 ...

  2. Linux学习笔记:nohup & 后台任务

    在linux中,使用nohup xxx.sh &可以将前台任务变成后台任务执行,如果只使用&的话,在突然断网或者关闭启动终端时,内核会向后台任务发送sighup信号,从而导致后台任务停 ...

  3. Effective STL 学习笔记: Item 22 ~ 24

    Effective STL 学习笔记: Item 22 ~ 24 */--> div.org-src-container { font-size: 85%; font-family: monos ...

  4. 常用SQL Server 语句

       常用SQL语句大全 1.//创建数据库 CREATE DATABASE DBName 2.//删除数据库 DROP DATABASE DBName 3.//备份SQL SERVER --- 创建 ...

  5. Spark(十四)SparkStreaming的官方文档

    一.SparkCore.SparkSQL和SparkStreaming的类似之处 二.SparkStreaming的运行流程 2.1 图解说明 2.2 文字解说 1.我们在集群中的其中一台机器上提交我 ...

  6. 003 JTA的使用与理解

    一:认识JTA 1.介绍 事物的ACID. 事务是计算机应用中不可或缺的组件模型,它保证了用户操作的原子性 ( Atomicity ).一致性 ( Consistency ).隔离性 ( Isolat ...

  7. (转)python随机数用法

    进行以下操作前先 import random ,导入random模块 1. random.seed(int) 给随机数对象一个种子值,用于产生随机序列. 对于同一个种子值的输入,之后产生的随机数序列也 ...

  8. C#语言-NPOI.dll导入Excel功能的实现

    前言:刚工作那会,公司有一套完善的MVC框架体系,每当有导入EXCEL功能要实现的时候,都会借用框架里自带的导入方法,一般三下五除二就完成了,快是快,可总是稀里糊涂的,心里很没有底.前几天,在另一个原 ...

  9. Java中面向对象的理解

    按照惯例,先做一个简单的介绍,现在开始学习 Thinging in Java 4 ,一边看,一边记录,我都不想给自己设定时间安排了,毕竟很少实现过.所以就这样吧!不定期的更新,我都会放到博客中的. 所 ...

  10. bzoj4668: 冷战 并查集按秩合并

    题目链接 bzoj4668: 冷战 题解 按秩合并并查集,每次增长都是小集合倍数的两倍以上,层数不超过logn 查询路径最大值 LCT同解 代码 #include<bits/stdc++.h&g ...