Visual C++开发工具与调试技巧整理[2]

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Visual C++开发工具与调试技巧整理[2]相关的知识,希望对你有一定的参考价值。

参考技术A

   如何添加Lib文件到当前工程

  单击菜单【Project】->【Settings…】弹出 Project Setting 对话框 切换到 Link 标签页 在 Object/library modules 处输入Lib文件名称 不同的Lib之间用空格格开

   如何快速删除项目下的Debug文件夹中临时文件

  在工作区的FileView视图中选中对应的项目 单击右键弹出菜单 选择【Clean(selection only)】菜单即可

   如何快速生成一个现有工程除了工程名外完全相同的新工程

  在新建工程的 New 对话框中选择 Custom Appwizard 项 输入新工程的名字 单击【OK】按钮 出现 Custom AppWizard 项 输入新工程的名字 单击【OK】按钮 出现 Custom AppWizard-Step of 对话框 选择 An existing Project 项 单击【Next】按钮 出现 Custom AppWizard-Step of 对话框 选择现有工程的工程文件名 最后单击【Finish】按钮 编译后就生成一个与现有工程相同但可以重新取名的工程AppWizard

  现在就可以项用MFC AppWizard一样用这个定制的向导 如果不想用了 可以在Visual C++ 安装目录下Common\\MSDev \\Template目录中删除该Wizard对应的 awx和 pdb文件

   如何解决Visual C++ 不正确连接的问题

  情景 明明改动了一个文件 却要把整个项目全部重新编译链接一次 刚刚链接好 一运行 又提示重新编译链接一次

  这是因为出现了未来文件(修改时间和创建时间比系统时间晚)的缘故 可以这样处理 找到工程文件夹下的debug目录 将创建和修改时间都比系统时间的文件全部删除 然后再从新 Rebuild All 一次

   引起LNK 的常见错误都有哪些

  遇到的LNK 错误主要为 unresolved external symbol symbol

  如果链接程序不能在所有的库和目标文件内找到所引用的函数 变量或标签 将产生此错误信息

  一般来说 发生错误的原因有两个 一是所引用的函数 变量不存在 拼写不正确或者使用错误 其次可能使用了不同版本的链接库 以下是可能产生LNK 错误的原因

  < >由于编码错误导致的LNK 错误

  ( )不相匹配的程序代码或模块定义( DEF)文件导致LNK 例如 如果在C++源文件了内声明了一变量 var 却试图在另一个文件内以变量 var 访问改变量

  ( )如果使用的内联函数是在 cpp文件内定义的 而不是在头文件内定义将导致LNK 错误

  ( )调用函数时如果所用的参数类型和头函数声明时的类型不符将会产生LNK 错误

  ( )试图从基类的构造函数或析构函数中调用虚拟函数时将会导致LNK 错误

  ( )要注意函数和变量的可公用性 只有全局变量 函数是可公用的 静态函数和静态变量具有相同的使用范围限制 当试图从文件外部方位任何没有在该文件内声明的静态变量时将导致编译错误或LNK 错误

  < >由于编译和联机的设置而造成的LNK 错误

  ( )如果编译时使用的是/NOD(/NODERAULTLIB)选项 程序所需要的运行库和MFC时将得到又编译器写入目标文件模块 但除非在文件中明确包含这些库名 否则这些库不会被链接进工程文件 这种情况下使用/NOD将导致LNK 错误

  ( )如果没有为wWinMainCRTStartup设定程序入口 在使用Unicode和MFC时将出现 unresolved external on _WinMain@ 的LNK 错误信息

  ( )使用/MD选项编译时 既然所有的运行库都被保留在动态链接库之内 源文件中对 func 的引用 在目标文件里即对 __imp__func 的引用 如果试图使用静态库LIBC LIB或LIBCMT LIB进行链接 将在__imp__func上发生LNK 错误 如果不使用/MD选项编译 在使用MSVCxx LIB链接时也会发生LNK 错误

  ( )使用/ML选项编译时 如用LIBCMT LIB链接会在_errno上发生LNK 错误

  ( )当编译调试版的应用程序时 如果采用发行版模态库进行链接也会产生LNK 错误 同样 使用调试版模态库链接发行版应用程序时也会产生相同的错误

  ( )不同版本的库和编译器的混合使用也能产生问题 因为新版的库里可能包含早先的版本没有的符号和说明

  ( )在不同的模块中使用内联和非内联的编译选项能够导致LNK 错误 如果创建C++库时打开了函数内联(/Ob 或/Ob ) 但是在描述该函数的相应头文件里却关闭了函数内联(没有inline关键字) 只是将得到错误信息 为避免该问题的发生 应该在相应的头文件中用inline关键字标志为内联函数

  ( )不正确的/SUBSYSTEM或ENTRY设置也能导致LNK 错误

   如何调试一个没有源码的exe文件调用的dll

  在Visual C++ 中 进入 Project Setting 对话框然后选择Debug标签页 通常Visual Studio默认 executable for debug session 为可执行文件名 但可以将他改成任何你想要的程序 甚至可以指定不同的工作目录以及传递参数到你的程序 这个技术常用来调试Dlls 名字空间扩展 对象和其他从某些EXE以及从第三方的EXE中调用的plug in程序

   Visual C++ 工程中的项目文件都表示什么

   opt 工程关于开发环境的参数文件 如工具条位置等信息

   aps(AppStudio File)资源辅助文件 二进制格式 一般不用去管它

   clw ClassWizard信息文件 实际上是INI文件格式 有兴趣可以研究一下 有时候ClassWizard出了问题 手工修改CLW文件可以解决 如果此文件不存在的话 每次用ClassWizard的时候回提示是否重建

   dsp(DevelopStudio Project) 项目文件 文本格式 不过不熟悉的不要手工修改

   dsw(DevelopStudio Workspace) 是工作区文件 其他特点和 dsp差不多

   plg 是编译信息文件 编译时的error和warning信息文件(实际上是一个文件) 一般用处不大 在单击菜单【Tool】->【Option】弹出的对话框里面有个选项可以控制这个文件的生成

   hpj(Help Project) 是生成帮助文件的工程 用microsoft Help Compiler可以处理

   mdp(Microsoft DevStudio Project) 是旧版本的项目文件 如果要打开此文件的话 会提示你是否转换成新的 dsp格式

   bsc 是用于浏览项目信息的 如果用Source Brower的话就必须有这个文件 如果不用这个功能的话 可以在Project Options里面去掉Generate Browse Info File 这样可以加快编译速度

   map是执行文件的映象信息记录文件 除非对系统底层 这个文件一般用不着

   pch(Pre Compiled File) 是与编译文件 可以加快编译速度 但是文件非常大

   pdb(Program Database) 记录了程序有关的一些数据和调试信息 在调试的时候可能有用

   exp 只有在编译DLL的时候才会生成 记录了DLL文件的一些信息 一般也没有用

   ncb 无编译浏览文件(no pile browser) 当自动完成功能出问题时可以删除此文件 编译工程后会自动生成

lishixinzhi/Article/program/net/201311/15642

Visual Studio调试之断点技巧篇补遗

原文链接地址:http://blog.csdn.net/Donjuan/article/details/4649372

讲完Visual Studio调试之断点技巧篇以后,翻翻以前看得一些资料和自己写的一些文章,发现还有几个关于中断程序的技巧在前面的文章里面遗漏了,决定还是在这里总结一下。当然啦,如果你知道这些技巧,忽略这篇文章好了,:)

在程序启动的时候将调试器附加上去

可能有人会对这个问题有一些争议,因为大部分情况下我们只需要在调试器(Debugger)里面直接启动被调试程序(Debuggee)就可以在程序启动前调试程序了。

但有些情况下,你是不能控制被调试程序(Debuggee)在什么时候启动的。例如在DCOM环境里面,DCOM客户端(Client)可以通过调用CoCreateInstanceEx(…, CTX_LOCAL_SERVER, …)启动DCOM服务器(Server),启动DCOM服务器的过程是在COM库中进行的, 你没有办法将在DCOM服务器的WinMain函数之前将你的调试器附加(Attach)上去。Windows提供了一个功能就是在一个程序启动的时候,自动将设置好的调试器附加到这个新启动的程序上去。这里我就是要介绍这个功能:

或者说你需要调试一个Windows服务的启动部分,在服务启动的时候,让调试器附加上去岂不是比在Start()函数里面打印很多跟踪信息要好很多?

在程序启动的时候将调试器附加上去实际上是Windows操作系统提供的功能,呃……当然,调试器之所以能工作,也是CPU和操作系统通力合作的结果,:)。因此你需要修改一些操作系统里面的设置:

1. 打开注册表编辑器(regedit.exe).

2. 找到键值HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows NT/CurrentVersion/Image File Execution Options/。

3. 新建一个键(Key),键名就是你要调试的程序的文件名,例如notepad.exe。

4. 然后在这个新建的键值(Key)下,在我们的例子里,这个键值是notepad.exe。新建一个字符串值(String Value)Debugger,值设置为你喜欢的调试器:

a. 如果选择Visual Studio的话,就是D:/Program Files/Microsoft Visual Studio 9.0/Common7/IDE/devenv.exe(假设你的Visual Studio安装在D盘)

b. 选择Windbg的话,就是c:/debuggers/windbg.exe(假设你的Windbg拷贝在c:/debuggers/目录里)。

设置好了以后,启动notepad.exe,这个时候你选择的调试器就会被Windows先启动起来,然后在notepad.exe的入口处中断。换句话说,所有的程序,都可以使用这种方法在启动的时候自动激活调试器,当然啦,如果你已经修复了你的问题,不需要调试器在程序启动之前启动的话,在注册表里面删掉那个键值就好了。

如何设置验尸调试(POSTMORTEM DEBUGGER)

首先先讲一下什么叫做验尸调试,大家应该都有这个体验,当一个程序突然崩溃的时候,Windows会不失时机弹出一个对话框,问你是否要发送错误报告给微软。其实这个对话框叫做Watson, 是Windows自带的一个非常简单的调试器,它的工作就是将程序的内存拷贝下来保存到一个文件当中。这个过程就是验尸调试的准备步骤,因为程序加载进内存以后,术语叫做进程,当进程崩溃的时候,就是意外死亡嘛,当然进程正常结束那叫做自然死亡。一般我们只对意外死亡的进程比较感兴趣,就跟电视里警匪片里面描写的那样,一个无辜的配角死掉了,警察第一步总是要保护现场,带尸体回去 ,让法医验尸。进程意外死亡的时候,Windows区别进程是否是意外死亡的方式很简单,就是看进程里面是否有未处理的异常。Windows也提供了一个选项,可以让你把犯罪现场--进程发生异常的时候的内存保留下来(进程的尸体),你可以在晚一点的时候来慢慢分析这个内存(比如看一看堆栈,一些变量什么的)--这个过程就叫做验尸。

验尸调试对下面这种情况很有帮助:

1. 重现很难重现的bug,比如说你有一个bug是随机出现,但是每次出现都会把程序搞死,与其绞尽脑汁去回忆重现步骤,还不如直接把犯罪现场保留下来,慢慢分析。

启动非托管程序的验尸调试功能

跟在程序启动时将调试器附加上去类似,验尸调试实际上也是Windows提供的功能,启动验尸调试,你需要修改下面的注册表设置:

在//HKEY_LOCAL_MACHINE/Software/Microsoft/Windows NT/CurrentVersion/AeDebug里面,分别创建下面两个键:

技术分享

如图所示:

技术分享

里面的键值说明一下:

  1. Debugger:指定了用来执行验尸调试的调试器文件名的完整路径,-p和-e是调试器的一些命令行参数,而%ld则是一个占位符,Windows会把死亡的进程的PID替换%ld这个值(读者如果熟悉批处理编程的话,就应该知道%ld实际上是批处理程序的参数的声明方式)。vsjitdebugger.exe是Visual Studio用来处理验尸调试的调试器名称,如果你安装了Visual Studio,VS的安装程序应该会自动为你设置好这个键。
  2. Auto:如果值是1的话,那么windows就会自动在进程死亡的时候,启动调试器;如果为0的话,就会打开一个对话框问你是否要执行验尸调试—但是Windows 7如果是这个选项的话,会直接禁用验尸调试,因此我推荐将Auto的值总是设置成1。

备注:对于偏好windbg的读者,你有两个方案将Windbg设置成默认的验尸调试程序:

  1. 直接执行  windbg –I   这个命令,注意I要大写。
  2. 将Debugger的键值设置为:"c:/Debuggers/windbg.exe" -p %ld -e %ld –g

设置好了以后,我们可以写一个测试程序来试一下刚才的设置:

Test.cpp

#include "stdafx.h"

int _tmain(int argc, _TCHAR* argv[])

{

int *p = NULL;

// 触发一个异常

*p = 0;

return 0;

}

使用命令cl.exe /Zi test.cpp编译好程序以后,执行test.exe,你应该就可以看到类似下面的现象了:

技术分享

启动托管程序的验尸调试功能

然而,上面的设置仅对native程序有效,如果要设置托管程序的默认验尸调试器,在//HKEY_LOCAL_MACHINE/Software/Microsoft/.NETFramework里面,分别创建下面两个键:

技术分享

使用上面的设置,你应该可以做所有非Winform托管程序的验尸调试了。

启动Winform程序的验尸调试功能

然而,当你的Win form程序崩溃(Crash)的时候,你会发现你设置的默认验尸调试器没有运行起来,原因是因为Win form程序默认禁用了即时调试(JIT Debug)的功能。因此要设置Win form程序的默认验尸调试器,你除了做上面的步骤以外,你还要将Win form程序的即时调试功能打开。打开的方法:

1. 修改你机器的machine.config文件,这样机器上所有的Win form程序都会将这个即时调试功能打开。在<configuration>里面添加下面一行:

<system.windows.forms jitDebugging="true" />

2. 修改单独程序的的app.config文件打开单个Win form程序的即时调试功能。在<configuration>里面添加下面一行:

<system.windows.forms jitDebugging="true" />

例如:

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

  <system.windows.forms jitDebugging="true" />

</configuration>

使用Visual Studio的RPC调试功能同时调试COM程序的客户端和服务端

参看我以前的文章:
http://blog.csdn.net/Donjuan/archive/2009/01/23/3851586.aspx

以上是关于Visual C++开发工具与调试技巧整理[2]的主要内容,如果未能解决你的问题,请参考以下文章

Visual Studio高效调试手段与技巧总结,值得收藏!

Microsoft Visual C++与Visual Studio的区别是啥?

我的全栈之路-C语言基础之Visual Studio 2019使用技巧

Visual C++和C++的区别

Visual Studio高级调试技巧

Visual Studio高级调试技巧