Matlab调用C程序

16 篇文章 1 订阅
16 篇文章 2 订阅

Matlab是矩阵语言,如果运算可以用矩阵实现,其运算速度非常快。但若运算中涉及到大量循环,Matlab的速度令人难以忍受的。当必须使用for循环且找不到对应的矩阵运算来等效时,可以将耗时长的函数用C语言实现,并编译成Mex文件,Matlab便可以像调用内建函数一样调用C编写的函数。Mex文件其实是一种动态链接库,旧版本Matlab可以直接调用.dll,新版本要调用.mexw32或.mexw64文件。

编译过程需要C语言编译器,在Matlab中键入mex –setup进行安装与配置。

MEX文件的源代码组成

(1)功能子程序。该过程包含了Mex文件实现计算功能的代码,是标准的C语言子程序。

(2)入口子程序。该过程提供功能子程序与Matlab之间的接口,以mexFunction函数实现。注意,入口过程的名称必须是mexFunction,并且包含四个参数,即

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

nrhs(left hand side): 输入参数的个数;

prhs是一个输入数组,其内容为指针,指向mxArray类型的数据(MATLAB中所有数据都是以矩阵的形式mxArray保存的)。

nlhs, plhs含义类似。

具体地,若在Matlab中执行[a,b]=test(c,d,e) ,则nlhs=2, nrhs=3,prhs[0]指向c,prhs[1]指向d,prhs[2]指向e(可以理解为:prhs[0]=&c, prhs[1]=&d, prhs[2]=&e),注意prhs是const指针数组,故不能改变其指向内容;函数返回时将plhs[0],plhs[1]指向的内容赋给a,b(可以理解为a=*plhs[0], b=*plhs[1])。

:新建add.c,源码如下:

#include "mex.h"  
double add(double x, double y)
{
    return x + y;
} 
void mexFunction(int nlhs,mxArray *plhs[], int nrhs,const mxArray *prhs[])
{
    double * a;
    double b, c;
    plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL);
    a = mxGetPr(plhs[0]);
    b = *(mxGetPr(prhs[0]));
    c = *(mxGetPr(prhs[1]));
    *a = add(b, c);
}

将add.c拷贝至Matlab当前目录,执行mex add.c,生成add.mexw64,该文件实现求和功能。此时便可在Matlab中调用该函数:

>> output = add(1.1, 2.2); 

分析:

#include "mex.h"

Mex源文件必须包含mex.h,该头文件提供了大量Matlab与C(或Fortran)语言的之间的接口函数,函数前缀有mex-和mx-两种,带mx-前缀的大多是对mxArray数据进行操作的函数,如mxIsDouble,mxCreateDoubleMatrix等;而带mex-前缀的则大多是与Matlab环境进行交互的函数,如mexPrintf,mexErrMsgTxt等。具体可参考Apiref.pdf

plhs[0] = mxCreateDoubleMatrix(1, 1,mxREAL);

建立一个1x1的double类型的矩阵,返回刚建立的mxArray的地址,赋给指针plhs[0];

a = mxGetPr(plhs[0]);

返回指针plhs[0]所指向矩阵的第一个实数的地址,并赋给a;

b = *(mxGetPr(prhs[0]));

获取指针prhs[0]指向矩阵的第一个实数,并赋给b;

*a = add(b, c);

调用C程序add,计算b,c之和并赋给a指向的内容;

例:新建myhilb.c,源码如下:

#include "mex.h"
void myhilb(double *y,int n)
{
    int i,j;
    for(i=0;i<n;i++)
        for(j=0;j<n;j++)
            *(y+j+i*n)=1/((double)i+(double)j+1);
}
void mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[])
{
    double x,*y;   
    if (nrhs!=1)
        mexErrMsgTxt("One inputs required.");
    if (!mxIsDouble(prhs[0])||mxGetN(prhs[0])*mxGetM(prhs[0])!=1)
        mexErrMsgTxt("Input must be scalars.");
    x=mxGetScalar(prhs[0]);
    plhs[0]=mxCreateDoubleMatrix(x,x,mxREAL);
    y=mxGetPr(plhs[0]);
    myhilb(y,(int)x);
}

将myhilb.c拷贝至Matlab当前目录,执行mex myhilb.c,生成myhilb.mexw64,该文件实现了计算Hilbert矩阵的功能(Hilbert矩阵:H(i,j)=1/(i+j-1))。

此时便可在Matlab中调用该函数:

>> output = myhilb (6);

分析:

mexFunction中进行了参数检查,函数mexErrMsgTxt显示出错信息后即退回到MATLAB。

mxGetScalar:获取输入矩阵第一个元素的实数部分;mxGetM:获取矩阵的行数。

为了测试一下Mex文件与m文件的速度差异,编写m文件并运行之:

tic
m=10000;
a=zeros(m,m);
for i=1:m
     for j=1:m
         a(i,j)=1/(i+j);
     end
end
toc

结果:Elapsed time is3.620924 seconds.

接着运行Mex文件

tic
output = myhl(10000);
toc

结果:Elapsed timeis 0.730596 seconds.

可以看出Mex文件与M文件速度差异很大。

VS2010生成Mex文件(本人64位操作系统)

上述利用Matlab编译生成Mex文件,同样也可以使用VS2010生成Mex文件,只不过需要对VS环境进行配置,过程如下:

1、  新建一个win32 控制台的dll 空项目”myhilb”;

2、  新建源文件myhilb.c,将上述myhilb.c内容拷进即可;

3、  添加.def文件,内容为:

LIBRARY

EXPORTSmexFunction

4、  配置项目属性, 打开项目属性配置页:

(1)C/C++—>常规—>附加包含目录,输入matlab下安装目录下\extern\include

本人输入E:\Matlab2010\Install\extern\include

(2)链接器->常规—>附加库目录,输入matlab下安装目录下\extern\lib\win64\microsoft

本人输入E:\Matlab2010\Install\extern\lib\win64\microsoft

(3)连接器 ->输入->附加依赖项,输入

libmx.lib

libeng.lib

libmat.lib

libmex.lib

(4)链接器->常规—>输出文件,输入$(OutDir)$(TargetName).mexw64(若此处不更改,可在生成dll文件后将后缀名改为mexw64即可,这也验证了Mex实际上就是DLL,只是后缀名不同罢了)

(5)链接器->高级—>目标计算机,设为MachineX64(32位系统不用更改)

设置好点击应用,执行了(5)的64位系统还需要在执行:

生成—>配置管理器—>活动解决平台,改为x64

5、按F7编译工程,会在Debug下生成.mexw64文件,如下图:


VS中单步调试Mex文件

在Matlab环境下使用 mex  –g myhilb.c命令进行调试,但无法加断点进行单步调试,故需转到VS环境下调试。

不管是利用VS还是利用Matlab生成Mex文件,只要有c源文件和Mex文件就可以利用VS对Mex源程序加断点进行单步调试(我们用上面myhilb.c和myhilb.mexw64做测试)。

1、将Matlab当前目录改为Mex文件(C文件)所在目录;

2、在VS2010中打开C文件,调试—>附加到进程,附加MATLAB.exe;

3、VS中在C源码中添加断点,在Matlab命令窗口调用Mex文件提供的接口;

如Matlab执行:out=myhilb(6);



此时,VS2010中便可按F10进行单步调试:


要说明的是,在调试阶段Matlab处于假死状态,另外,Matlab调用了Mex文件后需要执行clear all命令后才能删除Mex文件;

同样地,若利用VS生成Mex文件后直接将Matlab当前目录改至Debug目录进行调试,则调试完必须执行clear all指令才能重新编译工程。

参考:

http://blog.sina.com.cn/s/blog_468651400100coas.html

http://www.cppblog.com/xiaozhixd/articles/108490.html

http://www.linuxidc.com/Linux/2012-08/68148.htm

http://blog.sina.com.cn/s/blog_a7e72e940101cti9.html

http://blog.csdn.net/raodotcong/article/details/6317273


  • 9
    点赞
  • 69
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
MATLAB可以通过混合编程的方式调用C程序。混合编程的一般步骤如下: 1. 创建一个C文件,其中包含你想要在MATLAB调用的原始C语言函数\[2\]。 2. 编写mex接口函数,存为.c文件。这个文件可以在MATLAB中创建一个.c后缀的文件,或者在文本编辑器中编写后将后缀改为.c。接口函数中需要定义输入参数和输出参数,并调用原始C语言函数\[3\]。 3. 将接口函数复制到MATLAB文件夹中。 4. 在MATLAB中使用mex命令编译C文件,生成mex文件。编译命令的格式为:mex filename.c。 5. 在MATLAB调用mex文件,即可使用C程序的功能。 需要注意的是,MATLAB不能直接调用C语言的函数,需要将C语言代码编译成mex文件才可以调用。在编写mex接口函数时,需要使用MATLAB提供的辅助函数来处理输入参数和输出参数。编译生成的mex文件可以在MATLAB中像调用普通函数一样使用。 希望以上信息对你有帮助。 #### 引用[.reference_title] - *1* [MATLAB调用C语言程序—一个简单的例子](https://blog.csdn.net/weixin_43879841/article/details/107457403)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v4^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Matlab调用C函数(方法及实例)](https://blog.csdn.net/weixin_45926367/article/details/103593087)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v4^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

聚沙塔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值