《量化投资:以MATLAB为工具》

MATLAB技术论坛

 找回密码
 注册账号
查看: 25602|回复: 28
收起左侧

[教程] [原创]在Visual Studio中调试C/C++ mexFunction文件

    [复制链接]
发表于 2012-6-16 10:51:12 | 显示全部楼层 |阅读模式
先普及下几个术语,让大家有一个大概框架:
C/C++ MEX文件:也称为MEX源码文件,就是就是普通的fortran/C/C++文件,只是其中定义了一个mexFunction的接口,用于和MATLAB通讯,使用mex()函数可以将其编译为MATLAB MEX文件。至于如何书写mex源码文件,您可以看下MATLAB的帮助文档!

MATLAB MEX文件:也称为MEX二进制文件,是一种动态链接库,可以在MATLAB像普通函数一样直接调用或运行,windows平台下的扩展名为mexw32或者mexw64。使用mex()可以将MEX源码文件编译成mexw32,使用Coder工具箱可以将M文件编程mexw32。

mex()函数:MATLAB自带函数,用来将MEX源码文件编译成MEX二进制文件。

MEX函数库:在MEX源码文件中调用的MATLAB函数,主要进行和MATLAB的一些交流。

MX矩阵库:MATLAB为C/C++等提供了一些矩阵操作的库函数。

很多人都知道,使用mex()函数将C/C++源码文件编译成可以在MATLAB中直接运行的二进制mex文件。但是没有注意到还可以对生成的mex文件在Visual Studio进行调试!

本教程演示在Visual Studio 2010中调试yprime.c文件,该文件可以到matlabroot/extern/examples/mex/目录下找到,内容如下
  1. /*=================================================================
  2. *
  3. * YPRIME.C        Sample .MEX file corresponding to YPRIME.M
  4. *                Solves simple 3 body orbit problem
  5. *
  6. * The calling syntax is:
  7. *
  8. *                [yp] = yprime(t, y)
  9. *
  10. *  You may also want to look at the corresponding M-code, yprime.m.
  11. *
  12. * This is a MEX-file for MATLAB.  
  13. * Copyright 1984-2011 The MathWorks, Inc.
  14. *
  15. *=================================================================*/
  16. /* $Revision: 1.10.6.6 $ */
  17. #include <math.h>
  18. #include "mex.h"

  19. /* Input Arguments */

  20. #define        T_IN        prhs[0]
  21. #define        Y_IN        prhs[1]


  22. /* Output Arguments */

  23. #define        YP_OUT        plhs[0]

  24. #if !defined(MAX)
  25. #define        MAX(A, B)        ((A) > (B) ? (A) : (B))
  26. #endif

  27. #if !defined(MIN)
  28. #define        MIN(A, B)        ((A) < (B) ? (A) : (B))
  29. #endif

  30. static        double        mu = 1/82.45;
  31. static        double        mus = 1 - 1/82.45;


  32. static void yprime(
  33.                    double        yp[],
  34.                    double        *t,
  35.                     double        y[]
  36.                    )
  37. {
  38.     double        r1,r2;
  39.    
  40.     (void) t;     /* unused parameter */

  41.     r1 = sqrt((y[0]+mu)*(y[0]+mu) + y[2]*y[2]);
  42.     r2 = sqrt((y[0]-mus)*(y[0]-mus) + y[2]*y[2]);

  43.     /* Print warning if dividing by zero. */   
  44.     if (r1 == 0.0 || r2 == 0.0 ){
  45.         mexWarnMsgIdAndTxt( "MATLAB:yprime:divideByZero",
  46.                 "Division by zero!\n");
  47.     }
  48.    
  49.     yp[0] = y[1];
  50.     yp[1] = 2*y[3]+y[0]-mus*(y[0]+mu)/(r1*r1*r1)-mu*(y[0]-mus)/(r2*r2*r2);
  51.     yp[2] = y[3];
  52.     yp[3] = -2*y[1] + y[2] - mus*y[2]/(r1*r1*r1) - mu*y[2]/(r2*r2*r2);
  53.     return;
  54. }

  55. void mexFunction( int nlhs, mxArray *plhs[],
  56.                   int nrhs, const mxArray*prhs[] )
  57.      
  58. {
  59.     double *yp;
  60.     double *t,*y;
  61.     size_t m,n;
  62.    
  63.     /* Check for proper number of arguments */
  64.    
  65.     if (nrhs != 2) {
  66.             mexErrMsgIdAndTxt( "MATLAB:yprime:invalidNumInputs",
  67.                 "Two input arguments required.");
  68.     } else if (nlhs > 1) {
  69.             mexErrMsgIdAndTxt( "MATLAB:yprime:maxlhs",
  70.                 "Too many output arguments.");
  71.     }
  72.    
  73.     /* Check the dimensions of Y.  Y can be 4 X 1 or 1 X 4. */
  74.    
  75.     m = mxGetM(Y_IN);
  76.     n = mxGetN(Y_IN);
  77.     if (!mxIsDouble(Y_IN) || mxIsComplex(Y_IN) ||
  78.         (MAX(m,n) != 4) || (MIN(m,n) != 1)) {
  79.             mexErrMsgIdAndTxt( "MATLAB:yprime:invalidY",
  80.                 "YPRIME requires that Y be a 4 x 1 vector.");
  81.     }
  82.    
  83.     /* Create a matrix for the return argument */
  84.     YP_OUT = mxCreateDoubleMatrix( (mwSize)m, (mwSize)n, mxREAL);
  85.    
  86.     /* Assign pointers to the various parameters */
  87.     yp = mxGetPr(YP_OUT);
  88.    
  89.     t = mxGetPr(T_IN);
  90.     y = mxGetPr(Y_IN);
  91.         
  92.     /* Do the actual computations in a subroutine */
  93.     yprime(yp,t,y);
  94.     return;
  95.    
  96. }
复制代码
mex()编译生成mex二进制文件时,使用-g开关,则生成的mex文件由于依赖MATLAB某些文件,而不能直接在其他计算机的MATLAB运行,只能用于本地环境下调试。

Windows平台上调试
在Visual Studio 2005/2010平台上就可以调试C/C++源码MEX文件,楼主是用的是Visual Studio 2010,下面进行图解说明
(1)选择Visual C++ 2010作为默认编译器,在MATLAB命令行输入:
  1. >> mex -setup

  2. Welcome to mex -setup.  This utility will help you set up  
  3. a default compiler.  For a list of supported compilers, see  
  4. http://www.mathworks.com/support/compilers/R2012a/win32.html  
复制代码
(2)直接回车,MATLAB自动搜索系统中编译器。
  1. Please choose your compiler for building MEX-files:

  2. Would you like mex to locate installed compilers [y]/n?

  3. Select a compiler:
  4. [1] Intel Visual Fortran 12.0 (with Microsoft Visual C++ 2010 linker) in C:\Program Files\Intel\ComposerXE-2011\
  5. [2] Lcc-win32 C 2.4.1 in D:\Program\MATLAB\R2012a\sys\lcc
  6. [3] Microsoft Visual C++ 2010 in D:\Program\Visual Studio

  7. [0] None
复制代码
(3)楼主系统中安装两个编译器,其中Intel Visual Fortran是Fortran编译器,Visual C++ 2010是C/C++编译器。而LCC-Win32是MATLAB自带的C编译器(只能编译C,不能编译C++),不是楼主安装的。输入3,回车表示选择Visual C++ 2010作为C/C++默认编译器。
  1. Compiler: 3

  2. Please verify your choices:

  3. Compiler: Microsoft Visual C++ 2010  
  4. Location: D:\Program\Visual Studio
复制代码
(4)直接回车,确定并完成您的配置。
  1. Are these correct [y]/n?

  2. ***************************************************************************
  3.   Warning: MEX-files generated using Microsoft Visual C++ 2010 require
  4.            that Microsoft Visual Studio 2010 run-time libraries be  
  5.            available on the computer they are run on.
  6.            If you plan to redistribute your MEX-files to other MATLAB
  7.            users, be sure that they have the run-time libraries.
  8. ***************************************************************************


  9. Trying to update options file: C:\Users\Dynamic\AppData\Roaming\MathWorks\MATLAB\R2012a\mexopts.bat
  10. From template:              D:\Program\MATLAB\R2012a\bin\win32\mexopts\msvc100opts.bat

  11. Done . . .

  12. **************************************************************************
  13.   Warning: The MATLAB C and Fortran API has changed to support MATLAB
  14.            variables with more than 2^32-1 elements.  In the near future
  15.            you will be required to update your code to utilize the new
  16.            API. You can find more information about this at:
  17.            http://www.mathworks.com/help/techdoc/matlab_external/bsflnue-1.html
  18.            Building with the -largeArrayDims option enables the new API.
  19. **************************************************************************
复制代码
(5)使用-g开关编译yprime.c MEX源码文件,用于后面的调试。
  1. mex -g yprime.c
复制代码
此时当前目录下会生成一个yprime.mexw32文件,楼主的计算机是32位的,如果您是64位的操作系,那将生成一个yprime.mexw64的文件。
(6)启动Visual Studio,注意不要退出MATLAB,否则您会找不到相关进程的。
(7)在Visual Studio中进行菜单操作,Tools→Attach to Process...
mex-vs1.jpg
(8)在Attach to Process对话框中,选择MATLAB进程,点击“Attach(A)”按钮。
mex-vs2.jpg
(9)此时VS会自动加载所有相关数据,菜单操作,File→Open→File...选择MATLAB当前工作目录中的yprime.c文件。
mex-vs3.jpg
(10)您可以在yprime.c中任意设置断点,一般我们喜欢在mexFunction的开始位置就给一个断点。
mex-vs4.jpg
(11)在MATLAB中运行MEX二进制文件,比如输入:
  1. yprime(1,1:4)
复制代码
(12)程序会自动运行到VS中设置断点的位置,此时我们可以进行任何Visual Studio中的调试工作,比如查内存,看地址,读数据等等。
mex-vs5.jpg
(13)点击菜单操作,Debug→Contiue,将程序执行完毕,MATLAB命令窗口会显示如下内容:

  1. >> yprime(1,1:4)

  2. ans =

  3.     2.0000    8.9685    4.0000   -1.0947
复制代码

注意:如果您想将生成的mexw32文件发布给第三方,请重新使用mex()函数进行编译,使用-g开关生成的mexw32文件只能用于调试!

Linux平台上调试
由于楼主的Linux虚拟机上米有安装MATLAB,所以没法进行详细说明,将帮助文档中的内容复制粘贴一遍吧!

The GNU Debugger gdb, available on Linux systems, provides complete source code debugging, including the ability to set breakpoints, examine variables, and step through the source code line-by-line.

In this procedure, the MATLAB command prompt >> is shown in front of MATLAB commands, and linux> represents a Linux prompt; your system may show a different prompt. The debugger prompt is <gdb>.

To debug with gdb:
(1)Compile the source MEX-file with the -g option, which builds the file with debugging symbols included. For this example, at the Linux prompt, type:
  1. linux> mex -g yprime.c
复制代码

On a Linux 32–bit platform, this command creates the executable file yprime.mexglx.
(2)At the Linux prompt, start the gdb debugger using the matlab function -D option:
  1. linux> matlab -Dgdb
复制代码

(3)Start MATLAB without the Java Virtual Machine (JVM) by using the -nojvm startup flag:
  1. <gdb> run -nojvm
复制代码

(4)In MATLAB, enable debugging with the dbmex function and run your binary MEX-file:
  1. >> dbmex on
  2. >> yprime(1,1:4)
复制代码

(5)At this point, you are ready to start debugging.
It is often convenient to set a breakpoint at mexFunction so you stop at the beginning of the gateway routine.
  1. <gdb> break mexFunction
  2. <gdb> continue
复制代码

(6)Once you hit one of your breakpoints, you can make full use of any commands the debugger provides to examine variables, display memory, or inspect registers.
To proceed from a breakpoint, type:
  1. <gdb> continue
复制代码

(7)After stopping at the last breakpoint, type:
  1. <gdb> continue
复制代码

yprime finishes and MATLAB displays:
  1. ans =

  2.     2.0000    8.9685    4.0000   -1.0947
复制代码

(8)From the MATLAB prompt you can return control to the debugger by typing:
  1. >> dbmex stop
复制代码

Or, if you are finished running MATLAB, type:
  1. >> quit
复制代码

(9)When you are finished with the debugger, type:
  1. <gdb> quit
复制代码


You return to the Linux prompt.

Refer to the documentation provided with your debugger for more information on its use.

评分

参与人数 1贝壳 +3 贡献 +6 收起 理由
machreehappy + 3 + 6 鼓励帮助他人,我们共同进步

查看全部评分

发表于 2015-9-23 12:18:38 | 显示全部楼层
回复值得收藏学习
回复 支持 反对

使用道具 举报

发表于 2015-10-5 15:12:08 | 显示全部楼层
多谢楼主,哈哈
回复 支持 反对

使用道具 举报

发表于 2012-6-16 21:09:51 | 显示全部楼层
楼主,你好,我想问个比较偷懒的问题,matlaB里面的函数能不能编译生成c文件直接运行啊,像求逆类似的,用机器做毕竟比人写要来得容易点?
如果能的话,那这个机理是什么呢,是因为matlaB是用c等编写的,而还原回c文件了吗?
谢谢,原谅我的偷懒!
 楼主| 发表于 2012-6-16 21:27:40 | 显示全部楼层
stream2011 发表于 2012-6-16 21:09
楼主,你好,我想问个比较偷懒的问题,matlaB里面的函数能不能编译生成c文件直接运行啊,像求逆类似的,用机 ...

使用MATLAB Coder,可以将MATLAB转换成C/C++,生成的代码可以直接用于开发,不需要MATLAB的支持
发表于 2012-6-16 21:47:01 | 显示全部楼层
dynamic 发表于 2012-6-16 21:27
使用MATLAB Coder,可以将MATLAB转换成C/C++,生成的代码可以直接用于开发,不需要MATLAB的支持

强悍,我又找到方向了,表示感谢,
发表于 2012-6-18 06:59:54 | 显示全部楼层
精彩!学习啦!
发表于 2012-6-19 04:20:47 | 显示全部楼层
发表于 2012-6-27 08:21:27 | 显示全部楼层
太帅了!第一次知道!很有用啊。
发表于 2012-7-3 13:24:12 | 显示全部楼层
发表于 2012-7-27 23:58:15 | 显示全部楼层
谢谢楼主分享,学习了
发表于 2012-8-4 13:03:14 | 显示全部楼层
谢谢楼主分享,学习了
您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

QQ|网站地图|MATLAB技术论坛|Simulink仿真论坛 ( 蜀ICP备19014457号 

GMT+8, 2020-10-31 09:48 , Processed in 0.068950 second(s), 16 queries , Gzip On, MemCached On.

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表