• VC++调试说明


    1调试说明    1

    1.1 调试设置    1

    1.2 跟踪代码    2

    1.3 断点    2

    2模块生命周期    4

    2.1 exe模块    4

    2.2 dll模块    5

    3调试WinCE程序    7

    3.1 部署附加文件    7

    3.2 共享文件夹    8

    1调试说明

    1.1 调试设置

    使用Visual C++ 6.0打开一个项目,然后按下F5键即可开始调试程序。其实质就是启动VC++调试器,加载exe文件。具体加载哪个exe文件呢?请参考下面的项目设置界面

    图1.1 VC++6.0调试设置

    调试器加载的执行程序就是"Executable for debug session"指定的exe文件。对于exe项目而言,VC++会自动进行设置。对于dll项目而言,需要人工设置。

    "Working directory":调试器加载exe之前,会设置当前目录为该目录。如果该项为空,则设置当前目录为dsp所在目录。上图中,Working directoryC:,所以代码里GetCurrentDirectory获得的当前目录将是C:。代码fopen("File.txt","wb")) 创建的文件File.txt也将在C:下。

    "Program arguments":调试器将给exe传递命令行参数,也就是说将把这里的字符串传给 main(int argc,char *argv[]) 函数的argv

    一个exe项目和一个dll项目里,按下F5键后,调试器所做的工作并没有本质的区别——都是加载指定的 exe 文件。

    1.2 跟踪代码

    调试程序的时候,调试器会根据程序的执行进度自动跳到对应的代码行。为什么会这么神奇?因为编译器做了两个工作:

    1、执行程序用到的源文件(*.c*.cpp)被保存至pdb文件里;

    2、编译的时候,调试信息被写到了exedll文件里。

    因为有了pdb文件,调试器能够将断点定位到源文件。又因为有了调试信息,调试器能够将断点精确到行。

    也就是说:调试程序的时候要跟踪代码就必须保证pdb文件存在,并且是最新的。

    使用UltraEdit打开一个VC++6.0 Debug版的exedll文件。在文件末尾可以看到pdb文件的全路径。这就意味着pdb文件一旦生成就不要轻易移动,否则调试器将无法跟踪代码。非要移动pdb文件的话就一定要将它和exedll文件放在同一文件夹下。

    图1.2 pdb文件目录

    1.3 断点

    VC++6.0EVC++3.0/4.0的断点信息是保存在opt文件里的;VC++7.0及其以后版本的断点信息是保存在suo文件里的。当按下F5键开始调试的时候,调试器将加载这些断点信息,一旦代码执行到断点所在代码行的时候,调试器将暂停程序的执行。

    2模块生命周期

    模块就是exedll文件。当用户使用鼠标双击一个exe文件图标,要运行这个程序的时候,模块就具有了"生命"。本章将讨论一个模块在其生命周期内的关键事件点。理解这些对于调试程序将会有一定的帮助。

    2.1 exe模块

    exe模块的生命周期为:

    1、静态初始化全局变量,包括静态和动态;

    2、调用 main WinMain

    3、初始化静态变量;

    4、从 main WinMain 返回;

    5、销毁静态变量;

    6、销毁全局变量。

    举例说明:

    DWORD g_dwTickCount = GetTickCount();

    DWORD g_dwTemp = g_dwTickCount;

    int&GetStaticInt()

    {

    static int i = 0;

    return i;

    }

    int main()

    {

    GetStaticInt();

    }

    执行步骤如下:

    1、初始化全局变量

    首先是静态初始化,即将g_dwTickCount g_dwTemp全部初始化为零;

    接着是动态初始化。调用GetTickCount函数,并g_dwTickCount赋值。

    g_dwTemp = g_dwTickCount是一个危险的语句——假如g_dwTickCountg_dwTemp在不同的cpp文件里,则这两个全局变量的初始化顺序是无法预知的。如果g_dwTickCount先完成初始化g_dwTemp将得到预期的值,反之如果g_dwTemp先初始化则它始终为零。

    2、程序进入main函数

    3、初始化静态变量

    GetStaticInt里有静态变量i。第一次调用GetStaticInt时,该静态变量被创建。

    4、从main函数返回

    5、销毁静态变量

    这个程序里,就是销毁GetStaticInt函数里的静态变量i

    6、销毁全局变量

    即销毁全局变量g_dwTickCount g_dwTemp

    2.2 dll模块

    dll模块的生命周期与exe模块的生命周期是大致相同的:

    1、初始化全局变量;

    2、调用 DllMain(...,DLL_PROCESS_ATTACH,...)

    3、进程创建了一个新线程,会调用DllMain(...,DLL_THREAD_ATTACH,...)

    4、线程(非主线程)结束,会调用DllMain(...,DLL_THREAD_DETACH,...)

    5、初始化静态变量;

    6、调用 DllMain(...,DLL_PROCESS_DETACH,...)

    7、销毁静态变量;

    8、销毁全局变量。

    如果exe导入了dll,则其生命周期为

    1、静态/动态初始化 dll 全局变量,调用 DllMain(...,DLL_PROCESS_ATTACH,...)

    2、静态/动态初始化 exe 全局变量

    3exe 调用 main WinMain

    4、初始化静态变量;

    5exe main WinMain 返回

    6、销毁 exe 静态变量、销毁 exe 全局变量

    7dll 调用 DllMain(...,DLL_PROCESS_DETACH,...)

    8、销毁 dll 静态变量、销毁 dll 全局变量

    如果E.exe导入了A.dll,后者又导入了B.dll,则运行E.exe时,会首先加载B.dll,然后加载A.dll,最后加载E.exe

    3调试WinCE程序

    使用VC2005/VC2008调试WinCE程序比EVC++3.0/4.0要方便很多,而且调试效率也比较高。更为重要的是:VC2005/VC2008调试使用的虚拟机非常好,能够直接执行针对ARM芯片编译的执行程序。

    如果要调试的执行程序需要额外的动态库文件DacelLib.dll,该怎么办?解决方法有两个,一是调试时将DacelLib.dll部署到模拟器上;二是直接将DacelLib.dll复制到模拟器的共享文件夹内。

    3.1 部署附加文件

    进入项目属性页,在"配置属性"、"部署"下有附加文件。

    图3.1 部署附加文件

    下面是附加文件的例子

    msvcr90.dll|$(BINDIR)$(INSTRUCTIONSET)|%CSIDL_PROGRAM_FILES%$(ProjectName)|0

    atl90.dll|$(BINDIR)$(INSTRUCTIONSET)|%CSIDL_PROGRAM_FILES%$(ProjectName)|0

    msvcr90d.dll|$(BINDIR)$(INSTRUCTIONSET)|%CSIDL_PROGRAM_FILES%$(ProjectName)|0

    MFC90UD.dll|$(BINDIR)$(INSTRUCTIONSET)|%CSIDL_PROGRAM_FILES%$(ProjectName)|0

    其格式为:文件名|本机目录|部署目录|是否注册

    假定DacelLib.dll位于C:Share目录,想将其复制到智能设备的My Documents目录,则应该这样设置:

    DacelLib.dll|C:Share|My Documents|0

    如果DacelLib.dll是一个COM组件,则它需要注册,请将最后的0改为1

    3.2 共享文件夹

    如下图所示,单击模拟器的【文件】【配置】菜单项。

    图3.2 模拟器

    请设置共享文件夹

    图3.3 共享文件夹

    模拟器上将增加一个类似SD卡的目录——Storage Card。该目录下的内容与上图共享文件夹的内容保持一致。

    图3.4 Storage Card目录

  • 相关阅读:
    axios 封装
    全局重置 table 的 pageSizeOptions
    C7N 操作当前 table cell
    mongdb Atlas
    父级调用子级的方法,解决 observer 和 forwardRef 冲突报错
    C7N 重置 queryDataSet
    react 获取 search 方式传递的参数(URLSearchParams 和 querystring)
    持续集成管理平台的组成
    java 日期解决方案
    一些不常用的MySQL函数
  • 原文地址:https://www.cnblogs.com/hanford/p/6177885.html
Copyright © 2020-2023  润新知